Circular Queue Implementation Using Array in DSA Typescript - Time & Space Complexity
We want to understand how the time taken by circular queue operations changes as the queue size grows.
Specifically, how fast can we add or remove items when using an array in a circular way?
Analyze the time complexity of the enqueue and dequeue operations in this circular queue code.
class CircularQueue {
private arr: number[];
private front: number = -1;
private rear: number = -1;
private size: number;
constructor(size: number) {
this.size = size;
this.arr = new Array(size);
}
enqueue(value: number): boolean {
if ((this.rear + 1) % this.size === this.front) return false; // full
if (this.front === -1) this.front = 0;
this.rear = (this.rear + 1) % this.size;
this.arr[this.rear] = value;
return true;
}
dequeue(): number | null {
if (this.front === -1) return null; // empty
const value = this.arr[this.front];
if (this.front === this.rear) {
this.front = -1;
this.rear = -1;
} else {
this.front = (this.front + 1) % this.size;
}
return value;
}
}
This code adds (enqueue) and removes (dequeue) items in a fixed-size array used as a circular queue.
Look for loops or repeated steps inside enqueue and dequeue.
- Primary operation: Simple index calculations and assignments.
- How many times: Each enqueue or dequeue runs these steps 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 per enqueue/dequeue |
|---|---|
| 10 | About 5 steps |
| 100 | About 5 steps |
| 1000 | About 5 steps |
Pattern observation: The number of steps stays the same no matter how big the queue is.
Time Complexity: O(1)
This means each enqueue or dequeue operation takes the same short time no matter how many items are in the queue.
[X] Wrong: "Enqueue or dequeue must take 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 never scans or moves many items.
Understanding constant time operations like enqueue and dequeue in circular queues shows you can design efficient data structures that handle growing data smoothly.
"What if we changed the circular queue to a normal queue using a simple array without wrapping? 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 the rear reaches the end, no more elements can be added even if there is free space at the front.Step 2: Circular queue advantage
A circular queue connects the end of the array back to the front, allowing reuse of empty spaces and efficient use of the array.Final Answer:
It efficiently uses all available space by wrapping around the array. -> Option BQuick Check:
Circular queue = efficient space use [OK]
- Thinking circular queue sorts elements
- Believing it uses less memory than linear queue
- Assuming it stores different data types automatically
size with front and rear indices?Solution
Step 1: Understand full condition in circular queue
The queue is full when the next position of rear (rear + 1) modulo size equals front, meaning no space to insert.Step 2: Apply modulo for wrap-around
Using modulo ensures the rear wraps to the start of the array, so the condition is (rear + 1) % size === front.Final Answer:
if ((rear + 1) % size === front) -> Option CQuick Check:
Full condition = (rear + 1) % size === front [OK]
- Checking rear === front means empty, not full
- Using rear === size - 1 ignores wrap-around
- Checking front === -1 is for empty queue
front = 0 and rear = 3. After performing enqueue(10) and dequeue(), what are the new values of front and rear?Solution
Step 1: Perform enqueue(10)
rear moves from 3 to (3 + 1) % 5 = 4. So rear = 4, front remains 0.Step 2: Perform dequeue()
front moves from 0 to (0 + 1) % 5 = 1. So front = 1, rear remains 4.Final Answer:
front = 1, rear = 4 -> Option DQuick Check:
Enqueue rear+1=4, Dequeue front+1=1 [OK]
- Not applying modulo for wrap-around
- Updating front on enqueue instead of rear
- Confusing initial and final pointer positions
function dequeue() {
if (front === -1) return null;
const value = queue[front];
if (front === rear) {
front = rear = -1;
} else {
front = front + 1;
}
return value;
}Solution
Step 1: Analyze front update in dequeue
The code updates front as front = front + 1 without modulo, which can exceed array bounds.Step 2: Correct update with modulo
To wrap around in circular queue, front should be updated as front = (front + 1) % size.Final Answer:
Missing modulo operation when updating front, causing index overflow. -> Option AQuick Check:
Front update needs modulo [OK]
- Forgetting modulo causes index errors
- Confusing front and rear updates
- Wrong empty queue condition check
enqueue(5), enqueue(10), enqueue(15), dequeue(), enqueue(20), enqueue(25). What will be the final state of the queue array (index 0 to 3) and the positions of front and rear?Solution
Step 1: Perform enqueues and dequeue step-by-step
Start: front = -1, rear = -1, queue size = 4 - enqueue(5): front=0, rear=0, queue=[5,_,_,_] - enqueue(10): rear=1, queue=[5,10,_,_] - enqueue(15): rear=2, queue=[5,10,15,_] - dequeue(): front=1, queue unchanged - enqueue(20): rear=3, queue=[5,10,15,20] - enqueue(25): rear=(3+1)%4=0, queue[0]=25, queue=[25,10,15,20]Step 2: Final front and rear positions
front=1 (pointing to 10), rear=0 (pointing to 25). Queue array is [25,10,15,20].Final Answer:
Queue: [25, 10, 15, 20], front = 1, rear = 0 -> Option AQuick Check:
Wrap rear with modulo, front moves on dequeue [OK]
- Not wrapping rear index on enqueue
- Not updating front on dequeue
- Mixing up front and rear positions
Ready to prove it?
Pass the test and this pattern moves unknown
