Implement Stack Using Queue in DSA Rust - Time & Space Complexity
We want to understand how long it takes to do stack operations when using a queue to build it.
How does the time needed change as we add more items?
Analyze the time complexity of the following code snippet.
use std::collections::VecDeque;
struct MyStack {
queue: VecDeque<i32>,
}
impl MyStack {
fn new() -> Self {
MyStack { queue: VecDeque::new() }
}
fn push(&mut self, x: i32) {
self.queue.push_back(x);
for _ in 0..self.queue.len() - 1 {
if let Some(front) = self.queue.pop_front() {
self.queue.push_back(front);
}
}
}
}
This code uses one queue to simulate a stack. The push operation moves elements to keep the newest on front.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop inside the push method that moves elements from front to back.
- How many times: It runs once for each element already in the queue, so n-1 times if there are n elements.
Each push moves all existing elements to the back to keep the newest element at front.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 moves inside the loop |
| 100 | About 99 moves inside the loop |
| 1000 | About 999 moves inside the loop |
Pattern observation: The number of moves grows roughly the same as the number of elements already in the queue.
Time Complexity: O(n)
This means pushing an item takes time proportional to how many items are already in the stack.
[X] Wrong: "Push operation is always O(1) because it just adds one item."
[OK] Correct: Here, push moves all existing items to keep order, so it takes longer as the stack grows.
Understanding how to build one data structure using another and analyzing its cost is a great skill for interviews and real coding.
"What if we used two queues instead of one? How would the time complexity of push and pop change?"
Practice
Solution
Step 1: Understand stack and queue operations
A stack follows Last-In-First-Out (LIFO), while a queue follows First-In-First-Out (FIFO).Step 2: Simulate stack using queue(s)
By using one or two queues and carefully managing element order, we can mimic stack push and pop operations.Final Answer:
Use one or two queues to simulate stack operations like push and pop -> Option AQuick Check:
Stack via queue = simulate push/pop with queues [OK]
- Confusing stack and queue order
- Trying to sort elements instead of simulating stack
- Using stack to implement queue instead
Solution
Step 1: Identify correct queue type in Rust
VecDeque is the standard double-ended queue in Rust, suitable for queue operations.Step 2: Check correct syntax for mutable queue declaration
"let mut queue: VecDeque<i32> = VecDeque::new();" correctly declares a mutable queue of i32.Final Answer:
let mut queue: VecDeque<i32> = VecDeque::new(); -> Option CQuick Check:
VecDeque mutable queue declaration = let mut queue: VecDeque<i32> = VecDeque::new(); [OK]
- Using Vec instead of VecDeque for queue
- Missing mut keyword for mutable queue
- Wrong type annotations
use std::collections::VecDeque;
struct Stack {
queue: VecDeque<i32>,
}
impl Stack {
fn new() -> Self {
Stack { queue: VecDeque::new() }
}
fn push(&mut self, x: i32) {
self.queue.push_back(x);
let size = self.queue.len();
for _ in 0..size - 1 {
if let Some(val) = self.queue.pop_front() {
self.queue.push_back(val);
}
}
}
}
fn main() {
let mut stack = Stack::new();
stack.push(1);
stack.push(2);
println!("{:?}", stack.queue);
}Solution
Step 1: Trace push(1) operation
Push 1: queue = [1]. No rotation since size=1.Step 2: Trace push(2) operation
Push 2: queue = [1, 2]. Rotate size-1=1 times: pop_front 1, push_back 1 -> queue = [2, 1].Final Answer:
[2, 1] -> Option AQuick Check:
After push 1,2 queue = [2,1] [OK]
- Not rotating queue after push
- Confusing push_back and pop_front order
- Assuming queue keeps insertion order
fn pop(&mut self) -> Option<i32> {
self.queue.pop_back()
}Solution
Step 1: Understand queue ends in VecDeque
VecDeque supports pop_front() and pop_back(), but our stack top is at front after push rotation.Step 2: Check which end holds stack top
After push rotation, stack top is at front, so pop_front() removes top, not pop_back().Final Answer:
pop_back() removes from the wrong end; should use pop_front() -> Option BQuick Check:
Stack top at front, pop_front() needed [OK]
- Using pop_back() instead of pop_front()
- Not rotating queue after push
- Confusing queue ends
top method for a stack using a single queue in Rust, assuming push rotates the queue so the top is at the front?Solution
Step 1: Recall queue rotation after push
After push, queue is rotated so top element is at front.Step 2: Access top without removing
Use queue.front().cloned() to get top element without popping.Final Answer:
Return the element at the front of the queue without removing it using queue.front().cloned() -> Option DQuick Check:
Top element at front, use front().cloned() [OK]
- Using pop_front() which removes element
- Using back() which is bottom of stack
- Removing element instead of just viewing
Ready to prove it?
Pass the test and this pattern moves unknown
