10.4.5 Implementing ADTs with Arrays
A stack, queue or linked list describes how stored data behaves and which operations may be performed. An implementation explains how those abstract rules can be represented using actual storage.
One common implementation uses one-dimensional arrays together with pointer variables. The pointers record important positions such as the top of a stack, the front and rear of a queue, or the first active and unused nodes in a linked list.
By the end of this section, you should be able to:
- Explain how a 1D array and a top pointer can represent a stack.
- Trace front and rear pointers in an array-based queue.
- Explain how a circular queue reuses array positions.
- Trace a linked list represented by data and pointer arrays.
- Explain how a free list manages unused linked-list nodes.
- Compare parallel arrays with an array of node records.
- Recognise overflow and underflow conditions.
- Select a suitable array representation for a given situation.
From an Abstract Type to an Implementation
An Abstract Data Type defines the available operations and the way data is accessed. It does not require one particular internal representation.
Arrays provide one possible implementation. Pointer variables and index values are then used to preserve the required behaviour.
| ADT | Array storage | Control information | Behaviour preserved |
|---|---|---|---|
| Stack | One 1D array | Top pointer | Last item added is removed first |
| Queue | One 1D array | Front and rear pointers | First item added is removed first |
| Linked list | Data and pointer arrays, or an array of records | Start pointer and free-list pointer | Logical order is defined by links |
Implementing a Stack with a 1D Array
Stack items can be stored in consecutive array elements. A variable
called TopPointer identifies the array index containing
the current top item.
| Index | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| Stack | Map | Lens | Token | β | β | β |
In this example, TopPointer = 2, so
Token is the top item.
Push
To push a value, the program first checks that another array position is available. The top pointer is moved to the next position and the new item is stored there.
TopPointer = 2After pushing Solar:
TopPointer = 3 and
Stack[3] = "Solar"
Pop
To pop a value, the program reads the value at the current top position. The top pointer is then reduced so that the item below becomes the new top.
| Condition | Typical test | Meaning |
|---|---|---|
| Empty stack | TopPointer = -1 |
There is no item to pop. |
| Full stack | TopPointer = UpperBound |
There is no array position available for a push. |
Underflow: attempting to remove an item when the structure is empty.
Implementing a Linear Queue with an Array
An array-based queue normally requires two pointers:
-
FrontPointeridentifies the item that will leave next. -
RearPointeridentifies the most recently added item.
| Index | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| Queue | β | β | Nova | Orbit | Pixel | β |
If FrontPointer = 2 and
RearPointer = 4:
- Nova is the next value to be removed.
- Pixel is the most recently enqueued value.
- A new item would normally be stored after index 4.
Moving every remaining value towards index 0 would make those positions available, but repeated shifting is inefficient.
Reusing Space with a Circular Queue
A circular queue treats the array as though the position after the upper bound were the lower bound. The rear pointer can therefore wrap to the beginning of the array.
| Index | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| Queue | Rune | Signal | β | β | Quartz | River |
Suppose:
FrontPointer = 4RearPointer = 1
The queue is read from the front, wrapping after index 5:
Implementing a Linked List with Parallel Arrays
A linked list can be represented using two parallel 1D arrays:
- a data array containing the stored values;
- a pointer array containing the index of each node's successor.
The same index in both arrays represents one node.
| Index | Data | Next pointer | Current role |
|---|---|---|---|
| 0 | Mango | 4 | Active node |
| 1 | β | 3 | Unused node |
| 2 | Atlas | 0 | Active node |
| 3 | β | 5 | Unused node |
| 4 | Quartz | -1 | Final active node |
| 5 | β | -1 | Final unused node |
If StartPointer = 2, follow the active chain:
- Index 2 stores Atlas and points to index 0.
- Index 0 stores Mango and points to index 4.
- Index 4 stores Quartz and points to -1.
StartPointer. Do not read the active list in
numerical array-index order.
Managing Unused Nodes with a Free List
Unused array positions can form a second linked chain called the free list.
A variable called FreeListPointer identifies the first
available node. In the previous example:
FreeListPointer = 1
Free chain: 1 β 3 β 5 β NULL
Allocating a free node
-
Read the index stored in
FreeListPointer. - Save the next free index stored in that node.
-
Move
FreeListPointerto the next free index. - Store the new data in the allocated position.
- Change its pointer so that it joins the active list.
Returning a deleted node
- Bypass the node in the active list.
- Make the released node point to the old first free node.
-
Move
FreeListPointerto the released index.
Using an Array of Records
Instead of using two parallel arrays, each node can be represented by one record containing its data and pointer fields.
TYPE NodeType
DECLARE Data : STRING
DECLARE Next : INTEGER
ENDTYPE
DECLARE Node : ARRAY[0:5] OF NodeType
Individual fields can then be accessed using dot notation:
Node[2].Data
Node[2].Next
| Representation | Organisation | Advantage | Care needed |
|---|---|---|---|
| Parallel arrays | Data and pointers stored separately | Each field is easy to display independently | Matching indexes must remain aligned |
| Array of records | One record stores the complete node | Related fields remain grouped together | Record field notation must be used correctly |
Comparing the Implementations
| Feature | Stack | Queue | Linked list |
|---|---|---|---|
| Main pointer variables | Top | Front and rear | Start and free-list |
| Typical physical layout | Consecutive active elements | Consecutive or circular | Active nodes may be scattered |
| How order is represented | Array positions up to the top | Path from front to rear | Pointer chain from the start |
| Typical full condition | Top reaches the upper bound | No circular position remains free | The free list is empty |
| Typical empty condition | Top pointer is -1 | No active queue items remain | Start pointer is null |
Interactive: ADT Array Implementation Lab
Choose a structure and perform an operation. The widget shows the physical array, pointer state and logical order.
Common Mistakes and Misconceptions
- Describing an array as though it were the ADT itself.
- Forgetting the empty-stack value for the top pointer.
- Moving every queue item instead of using circular storage.
- Assuming a wrapped queue must have invalid pointer values.
- Tracing a linked list in physical index order.
-
Confusing
StartPointerwithFreeListPointer. - Allocating a free node without first preserving its next-free pointer.
- Returning a node to the free list before removing it from the active chain.
- Allowing corresponding parallel-array indexes to become misaligned.
Practice
Task 1: Stack trace
A stack uses indexes 0 to 4. It currently has
TopPointer = 1. Indexes 0 and 1 contain Cedar and
Flint.
- Show the result of pushing Glass.
- Show the result of one subsequent pop.
- State the overflow condition.
Task 2: Circular queue trace
A six-position circular queue has
FrontPointer = 4 and
RearPointer = 1. Active values occupy indexes
4, 5, 0 and 1.
- Write the logical index order.
- Which index is used by the next dequeue?
- Which index would be considered for the next enqueue?
Task 3: Linked-list trace
StartPointer = 3,
Pointer[3] = 0,
Pointer[0] = 5 and
Pointer[5] = -1.
- Write the active index chain.
- Explain why index 1 is not automatically the second node.
Task 4: Free-list allocation
FreeListPointer = 2,
Pointer[2] = 6 and
Pointer[6] = 4.
- Which index is allocated next?
- What is the new free-list pointer after allocation?
- How could a deleted node at index 1 be returned to the front of the free list?
Task 5: Compare representations
Explain one advantage of using an array of records instead of parallel arrays. Then explain why parallel arrays may still be convenient in a trace table.
Review
| Question | Strong answer should include |
|---|---|
| How can an array represent a stack? | Store active items consecutively and use a top pointer. |
| Why use a circular queue? | It reuses empty positions without moving all remaining values. |
| How is linked-list order represented? | A start pointer and next-pointer values form the active chain. |
| What is a free list? | A linked chain of unused positions available for new nodes. |
| Why use an array of records? | Each node's related data and pointer fields remain together. |
| What is overflow? | An insertion is attempted when no storage is available. |
| What is underflow? | A removal is attempted when the structure is empty. |