Bird
Raised Fist0
DSA Rustprogramming~10 mins

Circular Queue Implementation Using Array in DSA Rust - Execution Trace

Choose your learning style10 modes available
Concept Flow - Circular Queue Implementation Using Array
Initialize queue with fixed size
↓
Enqueue: Check if queue is full?
Yes→Reject enqueue
No↓
Add element at rear index
↓
Update rear index (rear = (rear + 1) % size)
↓
Increment count
↓
Dequeue: Check if queue is empty?
Yes→Reject dequeue
No↓
Remove element at front index
↓
Update front index (front = (front + 1) % size)
↓
Decrement count
↓
Repeat operations as needed
This flow shows how a circular queue uses a fixed-size array with front and rear pointers that wrap around using modulo to reuse space.
Execution Sample
DSA Rust
let mut queue = CircularQueue::new(5);
queue.enqueue(10);
queue.enqueue(20);
queue.dequeue();
queue.enqueue(30);
This code creates a circular queue of size 5, adds two elements, removes one, then adds another.
Execution Table
StepOperationFront IndexRear IndexCountQueue StatePointer ChangesVisual State
1Initialize queue000[_, _, _, _, _]front=0, rear=0, count=0Empty queue
2Enqueue 10011[10, _, _, _, _]rear=1, count=110 at index 0
3Enqueue 20022[10, 20, _, _, _]rear=2, count=220 at index 1
4Dequeue121[10, 20, _, _, _]front=1, count=1Removed 10 from index 0
5Enqueue 30132[10, 20, 30, _, _]rear=3, count=230 at index 2
6Enqueue 40143[10, 20, 30, 40, _]rear=4, count=340 at index 3
7Enqueue 50104[10, 20, 30, 40, 50]rear=0 (wrap), count=450 at index 4
8Enqueue 60104[10, 20, 30, 40, 50]No change, queue fullCannot enqueue 60, queue full
9Dequeue203[10, 20, 30, 40, 50]front=2, count=3Removed 20 from index 1
10Enqueue 60214[60, 20, 30, 40, 50]rear=1, count=460 at index 0 (wrap)
11Dequeue313[60, 20, 30, 40, 50]front=3, count=3Removed 30 from index 2
12Dequeue412[60, 20, 30, 40, 50]front=4, count=2Removed 40 from index 3
13Dequeue011[60, 20, 30, 40, 50]front=0 (wrap), count=1Removed 50 from index 4
14Dequeue110[60, 20, 30, 40, 50]front=1, count=0Removed 60 from index 0
15Dequeue110[60, 20, 30, 40, 50]No change, queue emptyCannot dequeue, queue empty
💡 Execution stops after last dequeue attempt because the queue is empty and no more operations are performed.
Variable Tracker
VariableStartAfter 2After 3After 4After 5After 6After 7After 8After 9After 10After 11After 12After 13After 14After 15
front000111112234011
rear012234000111111
count012123443432100
Key Moments - 3 Insights
Why does the rear index wrap back to 0 after reaching the end of the array?
Because the queue is circular, the rear index uses modulo operation to wrap around. See step 7 where rear moves from 4 to 0 to reuse space.
Why can't we enqueue when count equals the size even if there are empty slots?
Count tracks the number of elements. When count equals size, the queue is full. Even if front > rear, the circular logic prevents overwriting. See step 8 where enqueue is rejected.
Why does the front index move forward on dequeue but the array elements remain unchanged?
Dequeue moves front pointer to logically remove element; actual data stays until overwritten. See steps 4 and 9 where front moves but queue array shows old values.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table at step 7. What is the rear index after enqueueing 50?
A0
B4
C3
D1
💡 Hint
Check the 'Rear Index' column at step 7 in the execution table.
At which step does the queue become full for the first time?
AStep 8
BStep 6
CStep 7
DStep 5
💡 Hint
Look for when count equals the queue size in the execution table.
If we dequeue at step 15, what will be the count after this operation?
A1
BCannot dequeue
C0
D2
💡 Hint
Check the 'Count' and 'Operation' columns at step 15 to see if dequeue is possible.
Concept Snapshot
Circular Queue uses a fixed-size array with front and rear pointers.
Enqueue adds at rear, dequeue removes from front.
Both pointers wrap around using modulo to reuse space.
Count tracks number of elements to detect full/empty.
Enqueue rejected if full; dequeue rejected if empty.
Full Transcript
A circular queue uses an array with two pointers: front and rear. When we add (enqueue), we place the element at rear and move rear forward, wrapping around if needed. When we remove (dequeue), we take the element at front and move front forward, also wrapping around. We keep track of how many elements are in the queue with count. If count equals the size, the queue is full and we cannot add more. If count is zero, the queue is empty and we cannot remove. This way, the queue efficiently reuses space in the array by looping around.

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 efficiently uses all available space by wrapping around the array.
B. It allows storing different data types in the same queue.
C. It automatically sorts the elements in the queue.
D. It uses less memory than a linear queue.

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    It efficiently uses all available space by wrapping around the array. -> Option A
  4. Quick Check:

    Circular queue = efficient space use [OK]
Hint: Circular queue reuses space by wrapping indices [OK]
Common Mistakes:
  • Thinking circular queue sorts elements
  • Believing it uses less memory than linear queue
  • Assuming it stores different data types
2. Which of the following Rust code snippets correctly initializes a circular queue array of size 5 with front and rear pointers set to -1?
easy
A. let mut queue: [i32; 5]; let front: i32; let rear: i32;
B. let queue = Vec::new(); let front = 0; let rear = 0;
C. let mut queue: [i32; 5] = [1; 5]; let mut front: usize = 0; let mut rear: usize = 0;
D. let mut queue: [i32; 5] = [0; 5]; let mut front: i32 = -1; let mut rear: i32 = -1;

Solution

  1. Step 1: Check array initialization

    let mut queue: [i32; 5] = [0; 5]; let mut front: i32 = -1; let mut rear: i32 = -1; initializes a fixed-size array of 5 integers with all zeros, which is correct for a circular queue.
  2. Step 2: Check front and rear initialization

    let mut queue: [i32; 5] = [0; 5]; let mut front: i32 = -1; let mut rear: i32 = -1; sets front and rear to -1, indicating the queue is empty, which is standard practice.
  3. Final Answer:

    let mut queue: [i32; 5] = [0; 5]; let mut front: i32 = -1; let mut rear: i32 = -1; -> Option D
  4. Quick Check:

    Correct array and pointers initialization = let mut queue: [i32; 5] = [0; 5]; let mut front: i32 = -1; let mut rear: i32 = -1; [OK]
Hint: Initialize array with zeros and front/rear as -1 [OK]
Common Mistakes:
  • Using Vec instead of fixed-size array
  • Not initializing front and rear to -1
  • Leaving variables uninitialized
3. Consider this Rust code snippet for a circular queue of size 5. After these operations, what is the state of the queue array?
let mut queue = [0; 5];
let mut front: i32 = -1;
let mut rear: i32 = -1;

// Enqueue 10
if rear == -1 {
    front = 0;
    rear = 0;
    queue[rear as usize] = 10;
} else {
    rear = (rear + 1) % 5;
    queue[rear as usize] = 10;
}

// Enqueue 20
rear = (rear + 1) % 5;
queue[rear as usize] = 20;

// Dequeue
front = (front + 1) % 5;

// Enqueue 30
rear = (rear + 1) % 5;
queue[rear as usize] = 30;
medium
A. [10, 20, 30, 0, 0]
B. [0, 20, 0, 30, 0]
C. [10, 20, 0, 30, 0]
D. [0, 0, 20, 30, 0]

Solution

  1. Step 1: Trace enqueue and dequeue operations

    Initially front = -1, rear = -1, queue = [0,0,0,0,0]. - Enqueue 10: front=0, rear=0, queue[0]=10 -> [10,0,0,0,0] - Enqueue 20: rear=(0+1)%5=1, queue[1]=20 -> [10,20,0,0,0] - Dequeue: front=(0+1)%5=1 (10 removed logically) - Enqueue 30: rear=(1+1)%5=2, queue[2]=30 -> [10,20,30,0,0]
  2. Step 2: Determine final queue state

    Queue array is [10, 20, 30, 0, 0]. Although 10 is logically dequeued, it remains in the array until overwritten.
  3. Final Answer:

    [10, 20, 0, 30, 0] -> Option C
  4. Quick Check:

    After dequeue, front moves, old value stays [OK]
Hint: Remember dequeue moves front, old data stays until overwritten [OK]
Common Mistakes:
  • Assuming dequeued elements are erased immediately
  • Not applying modulo for rear and front
  • Mixing up front and rear positions
4. The following Rust code for enqueue in a circular queue has a bug. What is the error?
fn enqueue(queue: &mut [i32; 5], front: &mut i32, rear: &mut i32, value: i32) {
    if (*rear + 1) % 5 == *front {
        println!("Queue is full");
        return;
    }
    if *rear == -1 {
        *front = 0;
        *rear = 0;
    } else {
        *rear = (*rear + 1) % 5;
    }
    queue[*rear as usize] = value;
}
medium
A. The condition to check if queue is full is incorrect.
B. The initial check for empty queue should be *front == -1, not *rear == -1.
C. The queue array should be mutable but is not.
D. The modulo operation should use queue length minus one.

Solution

  1. Step 1: Analyze empty queue check

    The code checks if *rear == -1 to detect empty queue, but standard practice is to check if *front == -1 because front indicates the start of queue.
  2. Step 2: Understand impact of wrong check

    If *rear == -1 but *front is not -1, the queue might be incorrectly treated as empty, causing logic errors.
  3. Final Answer:

    The initial check for empty queue should be *front == -1, not *rear == -1. -> Option B
  4. Quick Check:

    Empty queue check uses front pointer [OK]
Hint: Empty queue means front == -1, not rear [OK]
Common Mistakes:
  • Checking rear instead of front for empty queue
  • Incorrect modulo usage
  • Not passing mutable references properly
5. You have a circular queue of size 4 implemented using an array. Initially, front = 2 and rear = 1 (meaning the queue is full). You perform one dequeue operation followed by two enqueue operations with values 50 and 60. What will be the final positions of front and rear pointers?
hard
A. front = 3, rear = 3
B. front = 3, rear = 0
C. front = 3, rear = 1
D. front = 2, rear = 3

Solution

  1. Step 1: Understand initial full queue state

    Queue size = 4, front = 2, rear = 1 means the queue is full because (rear + 1) % size == front ( (1+1)%4=2 ).
  2. Step 2: Perform dequeue operation

    Dequeue moves front forward: front = (2 + 1) % 4 = 3. Rear remains 1.
  3. Step 3: Perform first enqueue (50)

    rear = (1 + 1) % 4 = 2, insert 50 at index 2.
  4. Step 4: Perform second enqueue (60)

    rear = (2 + 1) % 4 = 3, insert 60 at index 3.
  5. Final Answer:

    front = 3, rear = 3 -> Option A
  6. Quick Check:

    After dequeue and two enqueues, pointers wrap correctly [OK]
Hint: Update front on dequeue, rear on enqueue with modulo [OK]
Common Mistakes:
  • Not applying modulo after pointer increment
  • Confusing front and rear updates
  • Assuming queue is empty after dequeue
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