Back to All Algorithms
Circular Queue
Category: Data Structures | Time: O(1) | Space: O(k)
Visualization
Visual representation of the data structure
0
1
2
3
4
About Circular Queue

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.

Code Editor
The code is for reference. Editing it won't affect the visualization.
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
Variable State
{
  "status": "Initializing Circular Queue",
  "size": 5
}
Circular Queue: How It Works
Last updated October 28, 2026

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

  1. The queue is full when (rear + 1) % size === front.
  2. Enqueue: if not full, set front = 0 when the queue was empty, then rear = (rear + 1) % size and store the value.
  3. The queue is empty when front === -1.
  4. Dequeue: read queue[front]; if front === rear, reset both to -1, otherwise front = (front + 1) % size.

Complexity

CaseCostWhy
EnqueueO(1)Index arithmetic only.
DequeueO(1)No shifting of elements.
Peek / isFull / isEmptyO(1)Simple comparisons.
SpaceO(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/rear alone both can look like front === rear; use -1 for empty (as here), a separate count, or leave one slot unused.
  • Forgetting % size when 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.
Worked Example: Circular Queue Dry Run
Generated from the same trace that drives the visualizer above, using the default input.

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
StepLineWhat happens
11status = Initializing Circular Queue, size = 5
29action = enqueue(10)
310condition = (rear + 1) % size === front -> false
413condition = front === -1 -> true
513front = 0
614rear = 0
715status = Enqueued 10
89action = enqueue(20)
910condition = (rear + 1) % size === front -> false
1013condition = front === -1 -> false
1114rear = 1
1215status = Enqueued 20
139action = enqueue(30)
1410condition = (rear + 1) % size === front -> false
1513condition = front === -1 -> false
1614rear = 2
1715status = Enqueued 30
1817action = dequeue()
1918condition = front === -1 -> false
2021dequeuedValue = 10
2122condition = front === rear -> false
2226front = 1
239action = enqueue(40)
2410condition = (rear + 1) % size === front -> false
2513condition = front === -1 -> false
2614rear = 3
2715status = Enqueued 40
289action = enqueue(50)
2910condition = (rear + 1) % size === front -> false
3013condition = front === -1 -> false
3114rear = 4
3215status = Enqueued 50
3317action = dequeue()
3418condition = front === -1 -> false
3521dequeuedValue = 20
3622condition = front === rear -> false
3726front = 2
3817action = dequeue()
3918condition = front === -1 -> false
4021dequeuedValue = 30

The remaining 8 key steps follow the same pattern. Press play in the visualizer to watch every step through to the result.

Frequently Asked Questions
About Circular Queue

What is a Circular Queue?

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's an efficient implementation of a queue using a fixed-size array, also known as a 'Ring Buffer'.

Why use a Circular Queue over a simple array-based queue?

A simple array-based queue can be inefficient. When you dequeue an element from the front, you either have to shift all other elements to the left (an O(n) operation) or leave empty space at the front. A circular queue solves this by allowing the `front` and `rear` pointers to 'wrap around' the array, making both enqueue and dequeue O(1) operations.

How do the 'front' and 'rear' pointers work?

The `front` pointer tracks the first element and the `rear` pointer tracks the last element. They are incremented using modulo arithmetic (`(pointer + 1) % size`). This allows them to wrap around to the beginning of the array when they reach the end, creating the circular behavior.

How do you check if a Circular Queue is full or empty?

A queue is empty when `front` is -1. A queue is full when the `rear` pointer is one position behind the `front` pointer. The condition for a full queue is `(rear + 1) % size === front`.

What are the time and space complexities?

The time complexity for `enqueue` and `dequeue` is O(1). The space complexity is O(k), where k is the capacity of the queue, as it uses a fixed-size array.

What are common applications?

Circular queues are used in many scenarios where a buffer of a fixed size is needed, such as in traffic light systems, CPU scheduling, and managing data buffers in streaming applications.

Where can I learn more?

You can find a more detailed explanation on GeeksforGeeks.