27.1 Introduction: The Queue ADT
A queue is a linear Abstract Data Type that holds items in the order they arrive and releases them in that same order. It follows the First-In, First-Out (FIFO) rule: the item that has waited longest is served next. Think of students lining up at the canteen — Musarrat joined first, so Musarrat is served first; anyone arriving later joins the back.
Because a queue is an abstract type, the syllabus does not care how you store it underneath — only that it behaves as FIFO. The two common implementations are a 1D array with two pointers (covered here) and a linked list.
| Term | Meaning |
|---|---|
| Queue | A FIFO ADT: items leave in the same order they entered. |
| FIFO | First-In, First-Out — the defining behaviour of a queue. |
| Front pointer | Index of the next item to be removed (the head of the line). |
| Rear pointer | Index of the last item added (the back of the line). |
| Enqueue | Add an item at the rear (the "insert" operation). |
| Dequeue | Remove and return the front item (the "delete" operation). |
| Peek / Front | Read the front item without removing it. |
| Overflow | Trying to enqueue when the queue is already full. |
| Circular queue | A queue whose last index wraps back to index 0 to reuse freed slots. |
27.2 How a Queue Works (FIFO + Two Pointers)
- A stack needed one pointer; a queue needs two — one for each end of the line.
- Picturing how
frontandrearmove is the whole game. - Get the picture right and the code writes itself.
A queue grows at the rear and shrinks at the front. Both pointers only ever move forward (to the right) in a basic linear queue. Watch them as three items are enqueued and one is dequeued:
Tracing enqueue(A), enqueue(B), enqueue(C) then dequeue() — watch front and rear
Empty
front=-1 rear=-1
enqueue(A), (B), (C)
front=0 rear=2
dequeue() → A
front=1 rear=2
enqueue moves rear forward; dequeue moves front forward. The two pointers chase each other to the right. A entered first, so A leaves first — that is FIFO.
- An empty queue has
front = -1andrear = -1. - The
frontpointer marks the next item to be removed; therearpointer marks the last item added. - Enqueue advances
rear; dequeue advancesfront.
- When a question gives you a queue diagram and asks you to “describe how two items are added”, name the rear pointer, say it advances, and say the new item is stored at the new rear position.
- Spell out each pointer movement — examiners award a mark per correct pointer step.
27.2 How a Queue Works (FIFO + Two Pointers)
27.3 The Linear Array Queue Class
- Before the clever circular version, you must be fluent with the plain linear queue.
- Every Paper 4 queue answer is built from these same five methods.
This class stores items in a fixed list and keeps two integer pointers. A count is also kept so “empty” and “full” are trivial to test.
class Queue:
def __init__(self, size=10):
self.items = [None] * size # fixed-size storage
self.maxSize = size # capacity
self.front = -1 # next item to remove
self.rear = -1 # last item added
def isEmpty(self):
return self.front == -1
def isFull(self):
return self.rear == self.maxSize - 1
def enqueue(self, item):
if self.isFull():
return "Queue Overflow"
if self.front == -1: # first item
self.front = 0
self.rear += 1 # advance rear, then store
self.items[self.rear] = item
def dequeue(self):
if self.isEmpty():
return "Queue Underflow"
item = self.items[self.front]
self.items[self.front] = None
if self.front == self.rear: # last item just left
self.front = self.rear = -1
else:
self.front += 1 # advance front
return item
def peek(self):
if self.isEmpty():
return "Queue is empty"
return self.items[self.front]- __init__: A fixed list of empty slots, the capacity, and both pointers set to -1 to mean “empty”.
- isEmpty: True when front = -1 — the single source of truth for “empty”.
- isFull: True when rear has reached the last index (maxSize - 1). Note: in a linear queue this can report “full” even when slots at the start are free — the problem we fix with a circular queue.
- enqueue: Reject if full. If this is the first item, set front = 0. Advance rear, then store.
- dequeue: Reject if empty. Read the front item, blank the slot. If that was the only item, reset both pointers to -1; otherwise advance front.
- peek: Return the front item without moving any pointer.
- In Cambridge pseudocode the empty test is usually
IF FrontPointer = -1and the full test isIF Length = MaxLength(using a length counter) orIF RearPointer = MaxLength - 1(linear). - State which convention you are using and stay consistent.
27.3 The Linear Array Queue Class
27.4 Enqueue & Dequeue, Step by Step
- Examiner focus: Paper 4 routinely gives you a half-written
EnqueueorDequeueroutine and asks you to complete it, or to write one from scratch. - The marks come from: the correct full/empty guard, advancing the right pointer, and storing/returning in the right order.
Enqueue (insert at the rear) — Cambridge pseudocode:
PROCEDURE Enqueue(NewItem)
IF Length = MaxLength THEN
OUTPUT "Queue full"
ELSE
Rear <- Rear + 1
IF Rear > MaxLength - 1 THEN // wrap (circular)
Rear <- 0
ENDIF
Queue[Rear] <- NewItem
IF Front = -1 THEN
Front <- 0
ENDIF
Length <- Length + 1
ENDIF
ENDPROCEDUREDequeue (remove from the front) — Cambridge pseudocode:
FUNCTION Dequeue() RETURNS STRING
IF Length = 0 THEN
RETURN "" // empty / null
ENDIF
ThisItem <- Queue[Front]
Front <- Front + 1
IF Front > MaxLength - 1 THEN // wrap (circular)
Front <- 0
ENDIF
Length <- Length - 1
RETURN ThisItem
ENDFUNCTION- enqueue(7): front -1→0, rear -1→0, store 7.
- enqueue(2): rear 0→1, store 2.
- dequeue(): read 7, front 0→1.
- enqueue(9): rear 1→2, store 9.
- First enqueue sets both pointers to 0; dequeue reads front then advances it.
- Enqueue: guard → advance rear (wrap) → store → maybe set front → length+1.
- Dequeue: guard → read front → advance front (wrap) → length-1 → return.
- The order of read/store versus pointer-move is what examiners check most.
27.4 Enqueue & Dequeue, Step by Step
27.5 The Wasted-Space Problem (Drift)
- A linear queue has a famous flaw.
- Understanding why it wastes space is exactly the reasoning that motivates the circular queue in the next section — and it is a popular short-answer question.
In a linear queue both pointers march to the right and never come back. After several dequeues the slots at the start are empty but unusable — rear can hit the end of the array and report “full” even though half the queue is free. We call this pointer drift or wasted space.
Linear queue drift: rear reached the last index, so no more can be added — even though two slots stand empty.
isFull() says TRUE, but slots 0 & 1 are free. Wasted space!
The circular queue fixes exactly this — pointers wrap back to index 0 so freed slots are reused.
27.5 The Wasted-Space Problem (Drift)
27.6 The Circular Queue (Wrap-Around)
- Examiner focus: The circular queue is the version Cambridge examines most.
- A real Paper 3 question states plainly: “the queue is circular so that locations can be reused.”
- You must be able to trace the wrap-around and write the MOD step.
A circular queue treats the array as a ring: when a pointer would step past the last index, it wraps back to index 0 using modulo arithmetic (pointer + 1) MOD maxSize. Freed slots at the start are reused, so no space is wasted. A count variable tells full from empty (both can have front == rear).
class CircularQueue:
def __init__(self, size=10):
self.queue = [None] * size
self.maxSize = size
self.head = 0 # front
self.tail = 0 # rear (next free slot)
self.count = 0 # items currently stored
def is_full(self):
return self.count == self.maxSize
def is_empty(self):
return self.count == 0
def enqueue(self, item):
if self.is_full():
return "Queue is full"
self.queue[self.tail] = item
self.tail = (self.tail + 1) % self.maxSize # wrap-around
self.count += 1
def dequeue(self):
if self.is_empty():
return "Queue is empty"
item = self.queue[self.head]
self.queue[self.head] = None
self.head = (self.head + 1) % self.maxSize # wrap-around
self.count -= 1
return item- In a circular queue,
head == tailhappens in two different situations: when the queue is completely empty and when it is completely full. - The pointers alone cannot tell these apart.
- Keeping a
countof stored items removes the ambiguity:count == 0means empty,count == maxSizemeans full.
- enq A,B,C: tail 0→1→2→3, count=3.
- deq, deq: removes A then B, head 0→1→2, count=1.
- enqueue(D): store at tail=3, tail→(3+1)%4=0, count=2.
- enqueue(E): store at tail=0 (wrapped!), tail→1, count=3.
- tail moves with (tail+1) MOD 4; watch it wrap from 3 to 0.
- When asked to “describe how two items are added to a circular queue”, mention: advance the rear/tail pointer, wrap with MOD if it passes the last index, store the item, and increase the count.
- A missing MOD step or a missing count update each loses a mark.
27.6 The Circular Queue (Wrap-Around)
27.7 Queues in Action — Applications
- Queues underpin print spoolers, CPU scheduling and breadth-first search.
- The practical tasks below are the kind of “use a queue to…” problems that appear in Paper 4.
- Dequeue all items, pushing each onto a stack. Then pop each from the stack and enqueue it. LIFO reverses the order.
- The last item pushed to the stack is popped first.
- Enqueue each name; while not empty, print “Serving:” and dequeue.
- A count attribute or len(self.queue) gives the number waiting.
- if n % 2 == 0: evenQ.enqueue(n) else: oddQ.enqueue(n).
- Test the smallest range first, then the middle, then the catch-all.
27.8 Full Exam-Style Question
- A booking program at moshikur.com stores up to 50 ticket records in a circular queue.
- It uses a 1D array
TicketQueue[0:49], an integerFrontPointer, an integerRearPointerand an integerLength.
(a) [2] State the values FrontPointer, RearPointer and Length should hold when the queue is empty, and explain why a circular queue needs a Length (or count) variable. (AO1)
(b) [5] Complete the pseudocode procedure Enqueue(NewID), which adds an ID if there is room, wraps the rear pointer when needed, otherwise outputs "Queue full". (AO2)
PROCEDURE Enqueue(NewID : INTEGER)
IF Length = .................... THEN
OUTPUT "Queue full"
ELSE
RearPointer <- (RearPointer + 1) ....................
TicketQueue[RearPointer] <- ....................
IF FrontPointer = -1 THEN
FrontPointer <- ....................
ENDIF
Length <- ....................
ENDIF
ENDPROCEDURE(c) [6] Write the function Dequeue() that returns the front ID, wraps the front pointer, updates Length, or returns -1 if the queue is empty. (AO3)
(d) [3] The queue (size 5) currently holds, from front to rear, IDs at indices 3, 4, 0 with FrontPointer = 3, RearPointer = 0, Length = 3. Show the pointer values after: Enqueue(77), Dequeue(). (AO2)
- (a) FrontPointer = -1, RearPointer = -1, Length = 0; Length needed because Front = Rear is ambiguous (empty or full).
- (b) IF Length = 50; RearPointer <- (RearPointer + 1) MOD 50; TicketQueue[RearPointer] <- NewID; FrontPointer <- 0; Length <- Length + 1.
- (c) IF Length = 0 RETURN -1; ThisID <- TicketQueue[FrontPointer]; FrontPointer <- (FrontPointer + 1) MOD 50; Length <- Length - 1; RETURN ThisID.
- (d) Enqueue(77): rear (0+1)%5=1, Length=4; Dequeue: front (3+1)%5=4, Length=3. Final: Front=4, Rear=1, Length=3.
✓ Key Points Summary
27.9 Practice Tasks
Fifteen exam-style tasks. Click Hint for bullet-point guidance, then Help to reveal a worked Python/pseudocode solution.
Question Bank
Answer all questions, then press Submit Quiz to see your score.
Question 1Multiple Choice
A queue follows which rule?
Question 2Multiple Choice
Which two pointers does a queue keep?
Question 3True / False
When the queue is empty, front = -1 and rear = -1.
Question 4Multiple Choice
Enqueue advances which pointer?
Question 5Multiple Choice
What is the drift problem in a linear queue?
Question 6Multiple Choice
How does a circular queue fix the drift problem?
Question 7Multiple Choice
Why does a circular queue use a count variable?
Question 8True / False
In a circular queue, (pointer + 1) MOD maxSize wraps the pointer back to 0.
Question 9Multiple Choice
What does peek() do in a queue?
Question 10Multiple Choice
Trace: linear queue size 4. After enqueue(7), enqueue(2), dequeue(), enqueue(9), what is front and rear?
Question 11Multiple Choice
Circular queue size 4, head=0, tail=0, count=0. After enqueue(A), enqueue(B), enqueue(C), dequeue(), dequeue(), enqueue(D), enqueue(E), where is E stored?
Question 12Multiple Choice
Which is a real-world use of a queue?
Answer all 12 questions to enable submission.