A Circular Queue is a linear data structure that follows the FIFO principle but its last position is connected back to the first position to make a circle. It is also called 'Ring Buffer'. It's an efficient implementation of a queue using a fixed-size array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
{
"status": "Initializing Circular Queue",
"size": 5
}Overview
A circular queue, or ring buffer, is a fixed-size queue whose array wraps around: when the rear reaches the last slot, the next element goes into slot 0 if it is free. Two indices, front and rear, move forward with modulo arithmetic, so no elements ever need to be shifted.
This solves the main weakness of a simple array queue, where dequeued slots at the start are wasted. It is the structure behind keyboard buffers, audio and network buffers, and producer-consumer queues in operating systems, because it never allocates memory after creation.
The visualizer uses a capacity of 5. The default commands enqueue 10, 20 and 30, dequeue once, enqueue 40 and 50 (filling slots 3 and 4), dequeue twice, and finally enqueue 60. Because slots 0 and 1 are free again, rear wraps to index 0 and 60 is stored there.
Step by step
- The queue is full when
(rear + 1) % size === front. - Enqueue: if not full, set
front = 0when the queue was empty, thenrear = (rear + 1) % sizeand store the value. - The queue is empty when
front === -1. - Dequeue: read
queue[front]; iffront === rear, reset both to -1, otherwisefront = (front + 1) % size.
Complexity
| Case | Cost | Why |
|---|---|---|
| Enqueue | O(1) | Index arithmetic only. |
| Dequeue | O(1) | No shifting of elements. |
| Peek / isFull / isEmpty | O(1) | Simple comparisons. |
| Space | O(k) | Fixed capacity k, allocated once. |
When to use it
- Fixed-size buffers for streaming data: audio, video, network packets, logs.
- Producer-consumer pipelines in embedded systems where dynamic allocation is avoided.
- Keeping the last k items, such as a moving average or recent-events history.
Common mistakes
- Telling full from empty: with
front/rearalone both can look likefront === rear; use -1 for empty (as here), a separate count, or leave one slot unused. - Forgetting
% sizewhen advancing an index runs off the end of the array. - A fixed capacity means enqueue can fail — decide whether to reject, overwrite the oldest item, or block.
A dry run is the best way to check your understanding of Circular Queue: follow each row, predict the next one, and compare. The run below takes 48 steps in total. The Line column refers to the line numbers in the code listing above.
- Input
- enqueue 10,enqueue 20,enqueue 30,dequeue,enqueue 40,enqueue 50,dequeue,dequeue,enqueue 60
- Result
- status = Operations complete
| Step | Line | What happens |
|---|---|---|
| 1 | 1 | status = Initializing Circular Queue, size = 5 |
| 2 | 9 | action = enqueue(10) |
| 3 | 10 | condition = (rear + 1) % size === front -> false |
| 4 | 13 | condition = front === -1 -> true |
| 5 | 13 | front = 0 |
| 6 | 14 | rear = 0 |
| 7 | 15 | status = Enqueued 10 |
| 8 | 9 | action = enqueue(20) |
| 9 | 10 | condition = (rear + 1) % size === front -> false |
| 10 | 13 | condition = front === -1 -> false |
| 11 | 14 | rear = 1 |
| 12 | 15 | status = Enqueued 20 |
| 13 | 9 | action = enqueue(30) |
| 14 | 10 | condition = (rear + 1) % size === front -> false |
| 15 | 13 | condition = front === -1 -> false |
| 16 | 14 | rear = 2 |
| 17 | 15 | status = Enqueued 30 |
| 18 | 17 | action = dequeue() |
| 19 | 18 | condition = front === -1 -> false |
| 20 | 21 | dequeuedValue = 10 |
| 21 | 22 | condition = front === rear -> false |
| 22 | 26 | front = 1 |
| 23 | 9 | action = enqueue(40) |
| 24 | 10 | condition = (rear + 1) % size === front -> false |
| 25 | 13 | condition = front === -1 -> false |
| 26 | 14 | rear = 3 |
| 27 | 15 | status = Enqueued 40 |
| 28 | 9 | action = enqueue(50) |
| 29 | 10 | condition = (rear + 1) % size === front -> false |
| 30 | 13 | condition = front === -1 -> false |
| 31 | 14 | rear = 4 |
| 32 | 15 | status = Enqueued 50 |
| 33 | 17 | action = dequeue() |
| 34 | 18 | condition = front === -1 -> false |
| 35 | 21 | dequeuedValue = 20 |
| 36 | 22 | condition = front === rear -> false |
| 37 | 26 | front = 2 |
| 38 | 17 | action = dequeue() |
| 39 | 18 | condition = front === -1 -> false |
| 40 | 21 | dequeuedValue = 30 |
The remaining 8 key steps follow the same pattern. Press play in the visualizer to watch every step through to the result.