A circular queue is a queue data structure implemented on a fixed-size array in which the rear pointer wraps around to the beginning of the array when it reaches the end. This reuses empty cells left by dequeued items, preventing the wasted-space problem of a straightforward linear array queue.
What is the problem with a simple linear queue?
In a standard linear queue backed by an array, you maintain two pointers: front (the index of the next item to remove) and rear (the index where the next item will be added).
Initial state: [_, _, _, _, _] front=0, rear=0, size=0
After enqueue A, B, C:
[A, B, C, _, _] front=0, rear=3, size=3
After dequeue A, dequeue B:
[_, _, C, _, _] front=2, rear=3, size=1
The cells at indices 0 and 1 are now empty — but rear cannot use them. If you keep enqueuing, rear eventually reaches the end of the array and reports "queue full", even though most of the array is wasted. A circular queue solves this.
How does a circular queue wrap its pointers?
In a circular queue, when rear reaches the last index of the array, it wraps back to index 0 — provided that cell is free. The same applies to front. This is achieved using the modulo operator:
rear = (rear + 1) % capacity
front = (front + 1) % capacity
Think of the array as a clock face. The rear pointer moves clockwise around the dial; when it passes 12 it does not fall off the clock — it starts again from 1.
Capacity = 5 cells (indices 0–4)
After enqueue A, B, C:
[A, B, C, _, _] front=0, rear=3, size=3
After dequeue A, dequeue B:
[_, _, C, _, _] front=2, rear=3, size=1
After enqueue D, E, F:
[F, _, C, D, E] front=2, rear=1, size=4
(rear wrapped from 4 → 0 → 1)
Now the space freed by dequeuing A and B is reused for F. The array is used efficiently.
What are the core operations on a circular queue?
| Operation | Action | Condition checked |
|---|---|---|
| Enqueue(item) | Place item at index rear; advance rear = (rear+1) % capacity |
Reject if full (size == capacity) |
| Dequeue() | Return item at index front; advance front = (front+1) % capacity |
Reject if empty (size == 0) |
| Peek() | Return item at front without removing it |
Reject if empty |
| IsFull() | Return size == capacity |
— |
| IsEmpty() | Return size == 0 |
— |
Tracking size as a separate counter is the simplest way to distinguish a full queue (front == rear, size == capacity) from an empty one (front == rear, size == 0). Without a size counter, you must keep one cell permanently empty as a sentinel.
How is a circular queue written in pseudocode?
CLASS CircularQueue
PRIVATE array[capacity]
PRIVATE front ← 0
PRIVATE rear ← 0
PRIVATE size ← 0
PRIVATE capacity ← 5
PROCEDURE enqueue(item)
IF size = capacity THEN
OUTPUT "Queue full — overflow"
ELSE
array[rear] ← item
rear ← (rear + 1) MOD capacity
size ← size + 1
END IF
END PROCEDURE
FUNCTION dequeue()
IF size = 0 THEN
OUTPUT "Queue empty — underflow"
RETURN null
ELSE
item ← array[front]
front ← (front + 1) MOD capacity
size ← size - 1
RETURN item
END IF
END FUNCTION
END CLASS
Where are circular queues used in real systems?
Circular queues appear wherever data arrives in a stream and must be processed in order, with a fixed buffer:
CPU scheduling — the operating system's round-robin scheduler holds runnable processes in a circular queue. Each process gets a fixed time slice; when its time is up it joins the back of the queue.
Keyboard buffer — keystrokes are stored in a small circular buffer. If you type faster than the application processes characters, the buffer fills; the oldest characters fall off the front as new ones arrive.
Audio streaming — a media player reads audio samples into a circular buffer. The playback thread consumes from the front; the network thread writes to the rear. This decouples the two speeds.
Printer spooler — print jobs queue in order; completed jobs vacate cells that new jobs can reuse.
How does a circular queue compare with other queue implementations?
| Implementation | Enqueue | Dequeue | Memory use | Wasted space? |
|---|---|---|---|---|
| Linear array queue | O(1) | O(n) or O(1) with shift | Fixed | Yes — cells behind front are unused |
| Circular array queue | O(1) | O(1) | Fixed | No — cells are reused |
| Linked-list queue | O(1) | O(1) | Dynamic | No — but pointer overhead per node |
The circular array queue gives O(1) enqueue and dequeue with no wasted space, using a fixed block of memory — making it ideal for systems where memory allocation must be predictable and fast.
Frequently asked questions
Why does a circular queue use the modulo operator?
The modulo operator (%) gives the remainder after division. (rear + 1) % capacity produces a number that counts up from 0 to capacity−1, then wraps back to 0. This is exactly the behaviour needed to make the array behave like a ring: after the last cell, the next position is the first cell again.
What is the difference between a circular queue and a circular buffer?
The terms are often used interchangeably. Technically, a circular buffer (also called a ring buffer) emphasises the fixed-capacity, overwrite-on-full behaviour used in audio and networking applications. A circular queue emphasises the FIFO (first-in-first-out) ordering and the error condition when full. In practice at GCSE, they describe the same underlying structure.
What happens when a circular queue is full?
When size == capacity, the queue is full and the enqueue operation should report an overflow error — it cannot insert another item until one has been dequeued. Some real-time systems choose to overwrite the oldest item instead of raising an error (a common choice in audio/video buffers where a stale sample is less harmful than a crash). For exam purposes, assume overflow raises an error unless stated otherwise.
How is a circular queue different from a standard queue?
A standard (linear) queue backed by a fixed array wastes space because the front pointer only moves forwards — cells behind it can never be reused. A circular queue solves this by allowing both front and rear pointers to wrap around, reusing freed cells. Both maintain FIFO order; the circular queue simply uses the available memory more efficiently.
Trace circular queues step by step with Professor Turing at aitutors.me — each step guided, never the answer handed straight to you.