At A Level you must write the algorithms that make each abstract data type work: insert into and delete from a stack, a queue and a linked list, and insert into and find in a binary tree. You also describe dictionaries and graphs, and show how one ADT can be built from another.
An abstract data type (ADT) is defined by its data and its operations, not by how it is stored. A stack (push, pop) needs an array and a top pointer; a circular queue (enqueue, dequeue) needs front and rear pointers that wrap round with MOD; a linked list needs an array of records with a start pointer, a free list pointer and a null pointer (−1) at the end; a binary search tree adds a left and a right pointer to each node, smaller values to the left. A dictionary stores key-value pairs, and a graph is a set of vertices joined by edges. ADTs can be built from other ADTs, for example a queue from two stacks.
In the lab, fill the circular queue, dequeue a few items and enqueue again: the rear pointer wraps round to index 0. The pseudocode below does exactly what the lab does, using a count to tell a full queue from an empty one.
DECLARE Stack : ARRAY[0:7] OF INTEGER
DECLARE TopPointer : INTEGER // -1 when the stack is empty
PROCEDURE Push(Item : INTEGER)
IF TopPointer = 7 THEN
OUTPUT "Stack full"
ELSE
TopPointer ← TopPointer + 1
Stack[TopPointer] ← Item
ENDIF
ENDPROCEDURE
FUNCTION Pop() RETURNS INTEGER
DECLARE Item : INTEGER
IF TopPointer = -1 THEN
OUTPUT "Stack empty"
RETURN -1
ENDIF
Item ← Stack[TopPointer]
TopPointer ← TopPointer - 1
RETURN Item
ENDFUNCTION
DECLARE Queue : ARRAY[0:5] OF INTEGER
DECLARE FrontPointer : INTEGER // starts at 0
DECLARE RearPointer : INTEGER // starts at -1
DECLARE NumberInQueue : INTEGER // starts at 0
PROCEDURE Enqueue(Item : INTEGER)
IF NumberInQueue = 6 THEN
OUTPUT "Queue full"
ELSE
RearPointer ← (RearPointer + 1) MOD 6
Queue[RearPointer] ← Item
NumberInQueue ← NumberInQueue + 1
ENDIF
ENDPROCEDURE
FUNCTION Dequeue() RETURNS INTEGER
DECLARE Item : INTEGER
IF NumberInQueue = 0 THEN
OUTPUT "Queue empty"
RETURN -1
ENDIF
Item ← Queue[FrontPointer]
FrontPointer ← (FrontPointer + 1) MOD 6
NumberInQueue ← NumberInQueue - 1
RETURN Item
ENDFUNCTION
In a circular queue, write (RearPointer + 1) MOD 6, not RearPointer + 1. Without MOD the pointer runs past index 5 even though spaces at the front are free.
In the lab, insert and delete items and watch only the pointers change. Below, the list is an array of records, each with a Data field and a Pointer field. The table shows the starting state used in the examples.
| Index | Data | Pointer |
|---|---|---|
| 0 | Cole | 6 |
| 1 | Ava | 4 |
| 2 | 5 | |
| 3 | Eli | −1 |
| 4 | Bea | 0 |
| 5 | 7 | |
| 6 | Dan | 3 |
| 7 | −1 |
StartPointer = 1, FreeListPointer = 2. The list is Ava → Bea → Cole → Dan → Eli → null; the free list is 2 → 5 → 7 → null.
TYPE ListNode
DECLARE Data : STRING
DECLARE Pointer : INTEGER
ENDTYPE
DECLARE List : ARRAY[0:7] OF ListNode
DECLARE StartPointer : INTEGER
DECLARE FreeListPointer : INTEGER
CONSTANT NullPointer = -1
FUNCTION FindItem(SearchItem : STRING) RETURNS INTEGER
DECLARE Current : INTEGER
Current ← StartPointer
WHILE Current <> NullPointer
IF List[Current].Data = SearchItem THEN
RETURN Current
ENDIF
Current ← List[Current].Pointer
ENDWHILE
RETURN NullPointer
ENDFUNCTION
PROCEDURE DeleteItem(DeleteThis : STRING)
DECLARE Current : INTEGER
DECLARE Previous : INTEGER
DECLARE Found : BOOLEAN
Current ← StartPointer
Previous ← NullPointer
Found ← FALSE
WHILE Current <> NullPointer AND Found = FALSE
IF List[Current].Data = DeleteThis THEN
Found ← TRUE
ELSE
Previous ← Current
Current ← List[Current].Pointer
ENDIF
ENDWHILE
IF Found = TRUE THEN
IF Previous = NullPointer THEN
StartPointer ← List[Current].Pointer
ELSE
List[Previous].Pointer ← List[Current].Pointer
ENDIF
List[Current].Pointer ← FreeListPointer
FreeListPointer ← Current
ENDIF
ENDPROCEDURE
Deleting the first node is a special case: there is no previous node, so the start pointer must change. Code that only updates List[Previous].Pointer fails for it.
Four quick checks. Each correct answer earns XP and records this skill on your profile.
In the lab's circular queue of 6 elements, RearPointer is 5. Where does the next item go if the queue is not full?
What must Pop check before it changes TopPointer?
When a node is deleted from a linked list, what happens to that node?
In the lab's binary search tree, where is a value equal to the root placed?
In the lab, insert a value into the binary tree and watch the comparisons from the root: left if smaller, right if larger or equal, until a null pointer is found. The new node is attached there. Then search for a value that is not in the tree.
TYPE TreeNode
DECLARE LeftPointer : INTEGER
DECLARE Data : INTEGER
DECLARE RightPointer : INTEGER
ENDTYPE
DECLARE Tree : ARRAY[0:9] OF TreeNode
DECLARE RootPointer : INTEGER
DECLARE FreePointer : INTEGER
CONSTANT NullPointer = -1
PROCEDURE InsertNode(NewItem : INTEGER)
DECLARE NewNode : INTEGER
DECLARE Current : INTEGER
DECLARE Previous : INTEGER
DECLARE GoLeft : BOOLEAN
IF FreePointer = NullPointer THEN
OUTPUT "Tree full"
ELSE
NewNode ← FreePointer
FreePointer ← Tree[NewNode].LeftPointer
Tree[NewNode].Data ← NewItem
Tree[NewNode].LeftPointer ← NullPointer
Tree[NewNode].RightPointer ← NullPointer
IF RootPointer = NullPointer THEN
RootPointer ← NewNode
ELSE
Current ← RootPointer
WHILE Current <> NullPointer
Previous ← Current
IF NewItem < Tree[Current].Data THEN
GoLeft ← TRUE
Current ← Tree[Current].LeftPointer
ELSE
GoLeft ← FALSE
Current ← Tree[Current].RightPointer
ENDIF
ENDWHILE
IF GoLeft = TRUE THEN
Tree[Previous].LeftPointer ← NewNode
ELSE
Tree[Previous].RightPointer ← NewNode
ENDIF
ENDIF
ENDIF
ENDPROCEDURE
When inserting into a tree or a linked list, take the node from the free list and update the free pointer before setting the new node's own pointers, or the rest of the free list is lost.
Unlocks once the four checks above are done. Worth more XP, written to A Level Paper 3 and Paper 4 standard.
Which ADT is most suitable for storing English words with their French translations?
Which is a key feature of a graph?
A binary search tree is built by inserting 10, 20, 30, 40, 50 in that order. What is the problem?
A stack is implemented using a linked list. Where should Push insert the new node?
This skill is now recorded on your profile. Keep the chain going.