A-Level Computer Science / Unit 10: Organising Data in Programs

10.4.5 Implementing ADTs with Arrays

πŸ”’ Lesson slides are available to signed-in users. Sign in

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.
Important scope: you should be able to describe and trace these implementations. You are not expected to memorise complete implementation algorithms for stacks, queues and linked lists.

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
Common misconception: an array is not automatically a stack, queue or linked list. The operations and pointer rules determine which ADT the array represents.

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.

Before pushing Solar: TopPointer = 2
After 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.
Overflow: attempting to add an item when the structure is full.
Underflow: attempting to remove an item when the structure is empty.
Exam tip: identify the top pointer before and after the operation. Do not only show the changed array value.

Implementing a Linear Queue with an Array

An array-based queue normally requires two pointers:

  • FrontPointer identifies the item that will leave next.
  • RearPointer identifies 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.
A linear queue can waste array positions. After several values have been removed, the rear pointer may reach the upper bound even though unused positions exist near the beginning.

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 = 4
  • RearPointer = 1

The queue is read from the front, wrapping after index 5:

Quartz β†’ River β†’ Rune β†’ Signal
Exam tip: begin at the front pointer and follow the circular index sequence until the rear pointer is reached.
Common mistake: a rear pointer smaller than the front pointer does not necessarily mean the queue is invalid. It can show that the queue has wrapped.

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:

  1. Index 2 stores Atlas and points to index 0.
  2. Index 0 stores Mango and points to index 4.
  3. Index 4 stores Quartz and points to -1.
Active list: Atlas β†’ Mango β†’ Quartz β†’ NULL
Trace from 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

  1. Read the index stored in FreeListPointer.
  2. Save the next free index stored in that node.
  3. Move FreeListPointer to the next free index.
  4. Store the new data in the allocated position.
  5. Change its pointer so that it joins the active list.

Returning a deleted node

  1. Bypass the node in the active list.
  2. Make the released node point to the old first free node.
  3. Move FreeListPointer to the released index.
Common mistake: the active list and free list use the same pointer array, but they are separate chains with separate starting pointers.

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
A strong comparison connects each pointer variable to its purpose. Merely listing the pointer names is not enough.

Interactive: ADT Array Implementation Lab

Choose a structure and perform an operation. The widget shows the physical array, pointer state and logical order.

Select an operation to update the implementation.
Physical representation

Stack array

Ready
Control information

Pointer state

Logical order

How to read this example

The implementation uses array indexes and pointer variables to preserve the abstract behaviour.

Step 1: inspect the starting state.

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 StartPointer with FreeListPointer.
  • 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.

  1. Show the result of pushing Glass.
  2. Show the result of one subsequent pop.
  3. 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.

  1. Write the logical index order.
  2. Which index is used by the next dequeue?
  3. 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.

  1. Write the active index chain.
  2. Explain why index 1 is not automatically the second node.

Task 4: Free-list allocation

FreeListPointer = 2, Pointer[2] = 6 and Pointer[6] = 4.

  1. Which index is allocated next?
  2. What is the new free-list pointer after allocation?
  3. 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.
Final exam tip: identify the array, name each pointer, state its value and explain precisely how one operation changes both the storage and pointer state.