Bird
Raised Fist0
DSA C++programming~15 mins

Circular Queue Implementation Using Array in DSA C++ - Deep Dive

Choose your learning style10 modes available
Overview - Circular Queue Implementation Using Array
What is it?
A circular queue is a special type of queue where the last position is connected back to the first position to make a circle. It uses an array to store elements and two pointers to track the front and rear positions. This design allows efficient use of space by reusing empty spots created by dequeued elements. It works like a normal queue but wraps around when it reaches the end of the array.
Why it matters
Without circular queues, simple queues using arrays waste space when elements are removed from the front, leaving unused spots at the beginning. Circular queues solve this by reusing those spots, making memory use efficient. This is important in systems with limited memory or where many enqueue and dequeue operations happen, like in printers or network buffers.
Where it fits
Before learning circular queues, you should understand basic queues and arrays. After mastering circular queues, you can explore linked list implementations of queues and advanced data structures like deques or priority queues.
Mental Model
Core Idea
A circular queue connects the end of an array back to the start, allowing continuous reuse of space as elements enter and leave.
Think of it like...
Imagine a round table where people sit in seats numbered 0 to N-1. When the last seat is filled, the next person sits back at seat 0 if it's empty, so the seats are reused in a circle.
Front and Rear pointers moving in a circle:

  [0] [1] [2] [3] [4]
   ↑           ↑
  Rear        Front

After some operations:

  [0] [1] [2] [3] [4]
       ↑           ↑
      Rear        Front

Pointers wrap around when reaching the end.
Build-Up - 7 Steps
1
FoundationBasic Queue Using Array
🤔
Concept: Introduce a simple queue using an array with front and rear pointers.
A queue stores elements in order. We use an array and two pointers: front points to the first element, rear points to the last. Enqueue adds at rear, dequeue removes from front. When rear reaches the end, no more elements can be added even if front has moved forward.
Result
Queue can add and remove elements but wastes space when front moves forward.
Understanding simple queues shows why space can be wasted, motivating circular queues.
2
FoundationLimitations of Simple Array Queue
🤔
Concept: Explain why a simple array queue wastes space after some dequeues.
When we dequeue elements, front moves forward, leaving empty spots at the start of the array. But rear cannot move back, so eventually, the queue appears full even if there is space at the front.
Result
Queue stops accepting new elements prematurely due to unused space at the front.
Recognizing this limitation helps understand the need for circular queues.
3
IntermediateCircular Queue Concept and Wrap Around
🤔Before reading on: do you think the rear pointer resets to zero automatically when it reaches the array end? Commit to yes or no.
Concept: Introduce the idea of wrapping rear and front pointers back to the start of the array.
In a circular queue, when rear or front reaches the last index, they wrap around to zero if space is available. This way, the queue uses the array in a circle, reusing empty spots.
Result
Queue can continue adding elements after wrapping around, using all available space.
Knowing pointers wrap around prevents wasted space and keeps the queue efficient.
4
IntermediateDetecting Full and Empty States
🤔Before reading on: do you think front == rear means the queue is empty or full? Commit to your answer.
Concept: Explain how to distinguish between full and empty states in a circular queue.
If front == rear, the queue can be empty or full. To avoid confusion, one slot is kept empty. The queue is full when (rear + 1) % size == front. It is empty when front == rear.
Result
Clear rules to check if queue is full or empty prevent errors.
Understanding this condition avoids bugs and ensures correct queue operation.
5
IntermediateImplementing Enqueue and Dequeue Operations
🤔Before reading on: do you think enqueue moves rear before or after inserting the element? Commit to your answer.
Concept: Show how to add and remove elements with pointer updates and wrap-around logic.
Enqueue: Check if full. If not, insert element at rear, then move rear forward with wrap-around. Dequeue: Check if empty. If not, remove element at front, then move front forward with wrap-around.
Result
Queue correctly adds and removes elements while pointers wrap around.
Knowing the order of pointer movement and insertion/removal is key to correct queue behavior.
6
AdvancedComplete Circular Queue Code in C++
🤔Before reading on: do you think the code should handle wrap-around using modulo operator or if-else? Commit to your answer.
Concept: Provide full runnable C++ code implementing circular queue with array.
class CircularQueue { int *arr; int size; int front, rear; public: CircularQueue(int s) { size = s; arr = new int[size]; front = rear = 0; } bool isFull() { return (rear + 1) % size == front; } bool isEmpty() { return front == rear; } void enqueue(int val) { if (isFull()) { std::cout << "Queue is full\n"; return; } arr[rear] = val; rear = (rear + 1) % size; } int dequeue() { if (isEmpty()) { std::cout << "Queue is empty\n"; return -1; } int val = arr[front]; front = (front + 1) % size; return val; } void display() { int i = front; std::cout << "Queue: "; while (i != rear) { std::cout << arr[i] << " -> "; i = (i + 1) % size; } std::cout << "null\n"; } }; int main() { CircularQueue q(5); q.enqueue(10); q.enqueue(20); q.enqueue(30); q.enqueue(40); q.display(); q.dequeue(); q.dequeue(); q.display(); q.enqueue(50); q.enqueue(60); q.display(); q.enqueue(70); // Should show full return 0; }
Result
Queue: 10 -> 20 -> 30 -> 40 -> null Queue: 30 -> 40 -> null Queue: 30 -> 40 -> 50 -> 60 -> null Queue is full
Seeing full code with wrap-around and conditions solidifies understanding and shows practical use.
7
ExpertPerformance and Memory Efficiency Insights
🤔Before reading on: do you think circular queues always outperform linked list queues in speed? Commit to your answer.
Concept: Discuss time complexity, memory use, and when circular queues excel or fall short.
Circular queues have O(1) enqueue and dequeue operations with fixed memory use. They avoid dynamic memory allocation overhead unlike linked lists. However, their fixed size can limit flexibility. In high-performance systems with known max size, circular queues are preferred for speed and cache efficiency.
Result
Circular queues offer fast, predictable performance but require size planning.
Knowing trade-offs helps choose the right queue type for real-world applications.
Under the Hood
Internally, the circular queue uses modular arithmetic to wrap the front and rear pointers within the array bounds. The array acts like a ring buffer. Enqueue inserts at rear, then rear moves forward modulo size. Dequeue removes at front, then front moves forward modulo size. The empty slot rule prevents front and rear pointers from overlapping ambiguously.
Why designed this way?
This design was created to solve the problem of wasted space in simple array queues. Using modulo arithmetic is efficient and simple to implement in hardware and software. Alternatives like linked lists use dynamic memory but have overhead. The empty slot trade-off simplifies full/empty detection.
Circular Queue Internal Structure:

  +-----------------------------+
  | Array of fixed size (N)     |
  |                             |
  |  [0] [1] [2] ... [N-1]      |
  +-----------------------------+
       ↑               ↑
     front           rear

Pointers move forward:
  front = (front + 1) % N
  rear = (rear + 1) % N

Empty slot between rear and front distinguishes full vs empty.
Myth Busters - 3 Common Misconceptions
Quick: Does front == rear always mean the queue is empty? Commit yes or no.
Common Belief:If front and rear pointers are equal, the queue must be empty.
Tap to reveal reality
Reality:Front == rear can mean either the queue is empty or full. To avoid confusion, circular queues keep one slot empty and use a special condition to detect full.
Why it matters:Misinterpreting this causes incorrect enqueue or dequeue operations, leading to data loss or crashes.
Quick: Can a circular queue dynamically grow like a linked list queue? Commit yes or no.
Common Belief:Circular queues can grow dynamically by resizing the array.
Tap to reveal reality
Reality:Circular queues have fixed size arrays and cannot grow dynamically without complex resizing logic, unlike linked list queues.
Why it matters:Assuming dynamic growth can cause buffer overflows or wasted memory if size is not planned.
Quick: Does enqueue always move rear before inserting the element? Commit yes or no.
Common Belief:Enqueue moves the rear pointer first, then inserts the element at the new rear position.
Tap to reveal reality
Reality:Enqueue inserts the element at the current rear position, then moves rear forward. Moving rear first would overwrite data.
Why it matters:Wrong pointer movement order causes data corruption or lost elements.
Expert Zone
1
The empty slot in circular queues is a deliberate trade-off to simplify full/empty detection, sacrificing one array slot for correctness.
2
Using modulo operator for pointer wrap-around is efficient but can be optimized with bitwise operations if size is a power of two.
3
In multithreaded environments, circular queues require careful synchronization or lock-free algorithms to avoid race conditions.
When NOT to use
Avoid circular queues when the maximum size is unknown or highly variable; linked list queues or dynamic queues are better. Also, if memory overhead is not a concern and frequent resizing is needed, dynamic structures are preferred.
Production Patterns
Circular queues are widely used in embedded systems, real-time audio/video buffers, network packet buffers, and producer-consumer problems where fixed-size, fast, and predictable queues are essential.
Connections
Ring Buffer
Circular queue is a type of ring buffer specialized for FIFO operations.
Understanding circular queues helps grasp ring buffers used in hardware and OS kernels for continuous data streams.
Modulo Arithmetic
Circular queue pointer wrap-around relies on modulo arithmetic to cycle indices.
Knowing modulo arithmetic is key to implementing circular data structures and algorithms efficiently.
Traffic Roundabouts (Urban Planning)
Both circular queues and roundabouts manage flow in a circular path to avoid congestion.
Studying circular queues can deepen understanding of flow control principles applicable in traffic systems and vice versa.
Common Pitfalls
#1Confusing full and empty states when front == rear.
Wrong approach:if (front == rear) { std::cout << "Queue is empty"; } else { // proceed }
Correct approach:if ((rear + 1) % size == front) { std::cout << "Queue is full"; } else if (front == rear) { std::cout << "Queue is empty"; } else { // proceed }
Root cause:Misunderstanding that front == rear can mean two different states without extra logic.
#2Moving rear pointer before inserting element in enqueue.
Wrong approach:rear = (rear + 1) % size; arr[rear] = val;
Correct approach:arr[rear] = val; rear = (rear + 1) % size;
Root cause:Incorrect order causes overwriting existing data.
#3Not handling wrap-around with modulo, causing out-of-bounds errors.
Wrong approach:rear = rear + 1; if (rear == size) rear = 0; // manual wrap-around without modulo
Correct approach:rear = (rear + 1) % size; // consistent modulo wrap-around
Root cause:Manual wrap-around can be error-prone and inconsistent.
Key Takeaways
Circular queues use an array in a looped fashion to efficiently reuse space after dequeues.
They rely on modulo arithmetic to wrap front and rear pointers within array bounds.
One slot is kept empty to clearly distinguish between full and empty states.
Enqueue inserts at rear then moves rear forward; dequeue removes at front then moves front forward.
Circular queues offer fast, fixed-size FIFO behavior ideal for systems with predictable memory needs.

Practice

(1/5)
1. What is the main advantage of using a circular queue over a simple linear queue when implemented using an array?
easy
A. It eliminates the need for front and rear pointers
B. It allows storing different data types in the same queue
C. It automatically sorts the elements in the queue
D. It efficiently uses the array space by reusing freed slots

Solution

  1. Step 1: Understand linear queue limitation

    In a linear queue using an array, once rear reaches the end, no more elements can be added even if there are empty slots at the front.
  2. Step 2: Circular queue advantage

    Circular queue connects the end of the array back to the front, allowing reuse of empty slots freed by dequeuing.
  3. Final Answer:

    It efficiently uses the array space by reusing freed slots -> Option D
  4. Quick Check:

    Space reuse = Advantage [OK]
Hint: Circular queue reuses space freed by dequeued elements [OK]
Common Mistakes:
  • Thinking circular queue sorts elements
  • Believing circular queue removes need for pointers
  • Assuming it supports multiple data types inherently
2. Which of the following is the correct condition to check if a circular queue is full when using an array of size n with front and rear pointers?
easy
A. front == (rear + 1) % n
B. rear == n - 1
C. front == rear
D. rear == (front + 1) % n

Solution

  1. Step 1: Understand full condition in circular queue

    In circular queue, queue is full when next position of rear is front, i.e., (rear + 1) modulo n equals front.
  2. Step 2: Match condition with options

    front == (rear + 1) % n matches this condition: front == (rear + 1) % n.
  3. Final Answer:

    front == (rear + 1) % n -> Option A
  4. Quick Check:

    Full condition = front == (rear + 1) % n [OK]
Hint: Full when front is next to rear in circular manner [OK]
Common Mistakes:
  • Using rear == n - 1 which is for linear queue
  • Confusing front == rear as full (actually empty)
  • Swapping front and rear in condition
3. Consider a circular queue of size 5 (indices 0 to 4). Initially, front = -1 and rear = -1. After the following operations:
enqueue(10); enqueue(20); enqueue(30); dequeue(); enqueue(40); enqueue(50); dequeue(); enqueue(60);
What will be the values of front and rear?
medium
A. front = 2, rear = 1
B. front = 2, rear = 0
C. front = 3, rear = 0
D. front = 1, rear = 4

Solution

  1. Step 1: Trace each operation and update pointers

    Start: front = -1, rear = -1
    enqueue(10): front=0, rear=0
    enqueue(20): rear=1
    enqueue(30): rear=2
    dequeue(): front=1
    enqueue(40): rear=3
    enqueue(50): rear=4
    dequeue(): front=2
    enqueue(60): rear=(4+1)%5=0
  2. Step 2: Final pointer values

    front = 2, rear = 0 which corresponds to front = 2, rear = 0.
  3. Final Answer:

    front = 2, rear = 0 -> Option B
  4. Quick Check:

    Trace pointers carefully [OK]
Hint: Track front and rear after each enqueue/dequeue [OK]
Common Mistakes:
  • Not updating rear circularly after last index
  • Confusing front and rear updates on dequeue
  • Ignoring initial front = -1 condition
4. The following code snippet is part of a circular queue implementation. Identify the bug:
void enqueue(int value) {
  if ((rear + 1) % size == front) {
    cout << "Queue is full" << endl;
    return;
  }
  if (front == -1) front = 0;
  rear = (rear + 1) % size;
  arr[rear] = value;
}
medium
A. No bug, code is correct
B. The front pointer should be updated after rear
C. The initial check for empty queue should be before full check
D. The condition to check full queue is incorrect

Solution

  1. Step 1: Analyze full queue condition

    The condition (rear + 1) % size == front correctly checks if queue is full in circular queue.
  2. Step 2: Check front pointer update and enqueue steps

    If queue is empty (front == -1), front is set to 0 before inserting.
    rear is updated circularly and value inserted at arr[rear].
  3. Final Answer:

    No bug, code is correct -> Option A
  4. Quick Check:

    Full check and pointers update are correct [OK]
Hint: Full check uses modulo; front updated only if empty [OK]
Common Mistakes:
  • Misplacing front update after rear
  • Incorrect full condition without modulo
  • Checking empty after full condition
5. You have a circular queue of size 6. After performing the following operations:
enqueue(5); enqueue(10); enqueue(15); dequeue(); dequeue(); enqueue(20); enqueue(25); enqueue(30); enqueue(35);
What will be the sequence of elements in the queue from front to rear?
hard
A. 20 -> 25 -> 30 -> 35
B. 10 -> 15 -> 20 -> 25 -> 30 -> 35
C. 15 -> 20 -> 25 -> 30 -> 35
D. 5 -> 10 -> 15 -> 20 -> 25 -> 30

Solution

  1. Step 1: Trace each operation and queue content

    Start empty.
    enqueue(5): queue = [5]
    enqueue(10): queue = [5,10]
    enqueue(15): queue = [5,10,15]
    dequeue(): removes 5, queue = [10,15]
    dequeue(): removes 10, queue = [15]
    enqueue(20): queue = [15,20]
    enqueue(25): queue = [15,20,25]
    enqueue(30): queue = [15,20,25,30]
    enqueue(35): queue = [15,20,25,30,35]
  2. Step 2: Check queue size and elements

    Queue size is 6, current elements are 5.
    From front to rear: 15 -> 20 -> 25 -> 30 -> 35
  3. Final Answer:

    15 -> 20 -> 25 -> 30 -> 35 -> Option C
  4. Quick Check:

    After dequeues, front moves; final elements start from 15 [OK]
Hint: Remove dequeued elements, then list remaining from front to rear [OK]
Common Mistakes:
  • Forgetting to remove dequeued elements
  • Listing elements before dequeue operations
  • Assuming queue is full and ignoring last enqueue
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard