622. Design Circular Queue - Detailed Explanation
Problem Statement
Description:
You are required to design a circular queue with a fixed size. The circular queue supports the following operations:
-
MyCircularQueue(k):
Initializes the circular queue with a maximum capacity of k. -
enQueue(value):
Inserts an element into the circular queue. Returnstrueif the operation is successful; otherwise, returnsfalse. -
deQueue():
Deletes an element from the circular queue. Returnstrueif the operation is successful; otherwise, returnsfalse. -
Front():
Gets the front item from the queue. If the queue is empty, return-1. -
Rear():
Gets the last item from the queue. If the queue is empty, return-1. -
isEmpty():
Checks whether the circular queue is empty. -
isFull():
Checks whether the circular queue is full.
Example 1:
- Input:
MyCircularQueue circularQueue = new MyCircularQueue(3); // set the size to be 3 circularQueue.enQueue(1); // return true circularQueue.enQueue(2); // return true circularQueue.enQueue(3); // return true circularQueue.enQueue(4); // return false, the queue is full circularQueue.Rear(); // return 3 circularQueue.isFull(); // return true circularQueue.deQueue(); // return true circularQueue.enQueue(4); // return true circularQueue.Rear(); // return 4 - Output:
The operations should behave as described above.
Constraints:
- 1 ≤ k ≤ 1000 (or similar bounds)
- All values inserted will be integers.
- The operations must work in O(1) time on average.
Hints
-
Hint 1:
Think of the queue as a fixed-size array. Use two pointers (or indices) to track the front and rear positions. -
Hint 2:
To support wrap-around, use modulo arithmetic when incrementing your pointers. This will help you simulate a circular structure within a linear array. -
Hint 3:
Be careful when checking if the queue is empty or full. One common trick is to maintain a count of the current number of elements or reserve one slot in the array to distinguish between full and empty cases.
Approach 1: Using an Array with Head, Tail, and Count
Idea
-
Data Structure:
Use a fixed-size array to store the elements. Maintain three variables:head: The index of the front element.tail: The index where the next element will be inserted.count: The current number of elements in the queue.
-
Operations:
-
enQueue(value):
If the queue is full (count == capacity), returnfalse. Otherwise, insert the value at thetailindex, then incrementtail(using modulo arithmetic to wrap around) and increase thecount. -
deQueue():
If the queue is empty (count == 0), returnfalse. Otherwise, remove the element at thehead, then incrementhead(using modulo arithmetic) and decrease thecount. -
Front():
Return the element atheadif not empty; otherwise, return-1. -
Rear():
The last element is at index(tail - 1 + capacity) % capacityif the queue is not empty. -
isEmpty() / isFull():
Use thecountvariable to check if the queue is empty or full.
-
Walkthrough Example
Let’s simulate operations on a circular queue of capacity 3:
-
Initialize:
head = 0,tail = 0,count = 0, and an array of size 3.
-
enQueue(1):
- Insert
1attailindex 0. - Set
tail = (0 + 1) % 3 = 1andcount = 1.
- Insert
-
enQueue(2):
- Insert
2attailindex 1. - Set
tail = (1 + 1) % 3 = 2andcount = 2.
- Insert
-
enQueue(3):
- Insert
3attailindex 2. - Set
tail = (2 + 1) % 3 = 0(wrap-around) andcount = 3.
- Insert
-
enQueue(4):
- The queue is full (
count == capacity), so returnfalse.
- The queue is full (
-
Rear():
- Calculate rear index as
(tail - 1 + capacity) % capacity = (0 - 1 + 3) % 3 = 2. - Return element at index 2, which is
3.
- Calculate rear index as
-
deQueue():
- Remove the element at
headindex 0. - Set
head = (0 + 1) % 3 = 1andcount = 2.
- Remove the element at
-
enQueue(4):
- Insert
4attailindex 0. - Set
tail = (0 + 1) % 3 = 1andcount = 3.
- Insert
-
Rear():
- Now the rear index is
(tail - 1 + capacity) % capacity = (1 - 1 + 3) % 3 = 3 % 3 = 0. - Return element at index 0, which is
4.
- Now the rear index is
Code Implementation
Python Code
Java Code
Complexity Analysis
-
Time Complexity:
Each operation—enQueue,deQueue,Front,Rear,isEmpty, andisFull—runs in O(1) time because all operations involve a fixed number of steps. -
Space Complexity:
The implementation uses O(k) space for the array, where k is the capacity of the circular queue.
Step-by-Step Walkthrough and Visual Example
Imagine a circular queue of capacity 3:
-
Initialization:
queue = [_, _, _],head = 0,tail = 0,count = 0.
-
After enQueue(1):
- Insert 1 at index 0.
queue = [1, _, _],head = 0,tail = 1,count = 1.
-
After enQueue(2):
- Insert 2 at index 1.
queue = [1, 2, _],head = 0,tail = 2,count = 2.
-
After enQueue(3):
- Insert 3 at index 2.
queue = [1, 2, 3],head = 0,tail = 0(wrap-around),count = 3.
-
Attempt enQueue(4):
- Queue is full (
count == capacity), so returnfalse.
- Queue is full (
-
Front() and Rear():
Front()returns element at index 0 →1.Rear()returns element at index(tail - 1 + capacity) % capacity = (0 - 1 + 3) % 3 = 2→3.
-
After deQueue():
- Remove element at index 0.
queueremains[1, 2, 3]butheadbecomes 1 andcount = 2.
-
After enQueue(4):
- Insert 4 at index 0 (tail position).
queue = [4, 2, 3],tailbecomes 1,count = 3.
-
Rear() now returns:
- Element at index
(tail - 1 + capacity) % capacity = (1 - 1 + 3) % 3 = 3 % 3 = 0→4.
- Element at index
Common Mistakes and Edge Cases
Common Mistakes
-
Confusing Empty and Full:
Not maintaining acountor using a reserved slot can lead to ambiguous conditions. Make sure you can distinguish between the two states. -
Incorrect Pointer Movement:
Forgetting to use modulo arithmetic when incrementingheadortailwill cause index out-of-bound errors. -
Mismanaging the Rear Calculation:
Sincetailpoints to the next insertion point, always adjust to find the last element when returningRear().
Edge Cases
-
Queue Capacity 1:
Test the behavior when there is only one slot. Ensure that bothenQueueanddeQueuework correctly. -
Multiple Wrap-Arounds:
Enqueue and dequeue several times to ensure that the circular nature (wrap-around) of the queue works as expected.
Alternative Variations and Related Problems
Variations
-
Dynamic Circular Queue:
Instead of a fixed capacity, design a circular queue that can expand dynamically. -
Deque (Double-Ended Queue):
Extend the design to support insertions and deletions at both the front and rear.
Related Problems for Further Practice
-
Design Stack Using Queues/Arrays:
Practice designing other data structures using basic arrays or queues. -
Implementing Circular Buffer:
Similar to circular queues, a circular buffer is used in system design for buffering data streams.
GET YOUR FREE
Coding Questions Catalog
$197

$78
$78