Circular Queue Implementation Using Array in DSA C++ - Time & Space Complexity
We want to understand how fast operations like adding or removing items work in a circular queue using an array.
How does the time to do these operations change as the queue grows?
Analyze the time complexity of the following circular queue operations.
class CircularQueue {
int front, rear, size;
int* arr;
public:
CircularQueue(int s) : front(-1), rear(-1), size(s) { arr = new int[s]; }
bool enqueue(int val) {
if ((rear + 1) % size == front) return false; // full
if (front == -1) front = 0;
rear = (rear + 1) % size;
arr[rear] = val;
return true;
}
bool dequeue() {
if (front == -1) return false; // empty
if (front == rear) front = rear = -1;
else front = (front + 1) % size;
return true;
}
};
This code adds (enqueue) and removes (dequeue) items in a circular queue using an array.
Look for loops or repeated steps inside the operations.
- Primary operation: Simple index calculations and assignments during enqueue and dequeue.
- How many times: Each operation runs once per call, no loops inside.
Each enqueue or dequeue does a fixed number of steps regardless of queue size.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5-6 steps per operation |
| 100 | 5-6 steps per operation |
| 1000 | 5-6 steps per operation |
Pattern observation: The number of steps stays the same no matter how big the queue is.
Time Complexity: O(1)
This means adding or removing an item takes the same short time no matter how many items are in the queue.
[X] Wrong: "Enqueue or dequeue takes longer as the queue gets bigger because the array is bigger."
[OK] Correct: The circular queue uses simple math to jump directly to the right spot, so it does not scan or move many items.
Knowing that circular queue operations run in constant time shows you understand efficient data handling, a key skill in many coding challenges.
"What if we changed the array to a linked list? How would the time complexity of enqueue and dequeue change?"
Practice
Solution
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.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.Final Answer:
It efficiently uses the array space by reusing freed slots -> Option DQuick Check:
Space reuse = Advantage [OK]
- Thinking circular queue sorts elements
- Believing circular queue removes need for pointers
- Assuming it supports multiple data types inherently
n with front and rear pointers?Solution
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.Step 2: Match condition with options
front == (rear + 1) % n matches this condition: front == (rear + 1) % n.Final Answer:
front == (rear + 1) % n -> Option AQuick Check:
Full condition = front == (rear + 1) % n [OK]
- Using rear == n - 1 which is for linear queue
- Confusing front == rear as full (actually empty)
- Swapping front and rear in condition
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?Solution
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=0Step 2: Final pointer values
front = 2, rear = 0 which corresponds to front = 2, rear = 0.Final Answer:
front = 2, rear = 0 -> Option BQuick Check:
Trace pointers carefully [OK]
- Not updating rear circularly after last index
- Confusing front and rear updates on dequeue
- Ignoring initial front = -1 condition
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;
}Solution
Step 1: Analyze full queue condition
The condition (rear + 1) % size == front correctly checks if queue is full in circular queue.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].Final Answer:
No bug, code is correct -> Option AQuick Check:
Full check and pointers update are correct [OK]
- Misplacing front update after rear
- Incorrect full condition without modulo
- Checking empty after full condition
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?
Solution
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]Step 2: Check queue size and elements
Queue size is 6, current elements are 5.
From front to rear: 15 -> 20 -> 25 -> 30 -> 35Final Answer:
15 -> 20 -> 25 -> 30 -> 35 -> Option CQuick Check:
After dequeues, front moves; final elements start from 15 [OK]
- Forgetting to remove dequeued elements
- Listing elements before dequeue operations
- Assuming queue is full and ignoring last enqueue
Ready to prove it?
Pass the test and this pattern moves unknown
