| Implementation | Enqueue | Dequeue | Peek | Space | Notes |
|---|---|---|---|---|---|
| Library (Deque) | Highly optimized. Python uses Linked List blocks; Rust uses Ring Buffer. | ||||
| Circular Queue | Strict . No memory allocation overhead during runtime. Fixed size . | ||||
| Queue using Stacks | Amortized | Amortized | Worst case for a single dequeue is , but average is . |
Detailed
1. Library & Circular Queue (Strict )
These implementations track the head and tail pointers/indices.
- Enqueue: We calculate the index/pointer and insert. No loops. .
- Dequeue: We calculate the index/pointer and remove. No loops. .
- Note: Rust’s
VecDequemight occasionally resize (grow), making enqueue Amortized , but this is standard for all dynamic arrays.
2. Queue using Stacks (Amortized )
This is the most common follow-up question in interviews.
Why is it Amortized ?
- Enqueue: We simply push to
s1. This is always . - Dequeue (Worst Case): If
s2is empty, we must move all items froms1tos2. This takes . - Dequeue (Best Case): If
s2has items, we just pop one. This takes .
The Math (Amortized Analysis):
Consider the lifecycle of a single element X:
- Pushed onto
s1(Cost: 1) - Popped from
s1(Cost: 1) - Pushed onto
s2(Cost: 1) - Popped from
s2(Cost: 1)
Total operations for X over its entire life = 4 operations.
Since 4 is a constant, the average cost per element is .