Queue Using Two Stacks in DSA C - Time & Space Complexity
We want to understand how fast operations run when we build a queue using two stacks.
Specifically, how does the time to add or remove items change as the queue grows?
Analyze the time complexity of the following code snippet.
// Push element x to the back of queue
void enqueue(Stack* s1, int x) {
push(s1, x);
}
// Remove element from front of queue
int dequeue(Stack* s1, Stack* s2) {
if (isEmpty(s2)) {
while (!isEmpty(s1)) {
push(s2, pop(s1));
}
}
return pop(s2);
}
This code uses two stacks to create a queue. Enqueue adds to the first stack. Dequeue moves all items to the second stack if empty, then pops from it.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Moving all elements from the first stack to the second stack during dequeue when the second stack is empty.
- How many times: This moving happens only when the second stack is empty, not every dequeue call.
When the second stack is empty, dequeue moves all n elements once, which takes n steps. But this happens only after n enqueues.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 moves spread over dequeues |
| 100 | About 100 moves spread over dequeues |
| 1000 | About 1000 moves spread over dequeues |
Pattern observation: Although some dequeues take longer, on average each operation takes constant time because moves are spread out.
Time Complexity: O(1) amortized
This means each enqueue or dequeue takes constant time on average, even if some dequeues take longer occasionally.
[X] Wrong: "Every dequeue takes O(n) time because it moves all elements."
[OK] Correct: The moving happens only when the second stack is empty, so the cost is spread out over many dequeues, making average time constant.
Understanding amortized time helps you explain why some operations seem slow but are efficient overall, a key skill in coding interviews.
What if we used three stacks instead of two? How would the time complexity change?
Practice
Queue Using Two Stacks?Solution
Step 1: Understand queue order
A queue follows FIFO (First In First Out) order, meaning the first element added is the first to be removed.Step 2: Use two stacks to reverse order twice
One stack reverses the order when pushing elements, and the second stack reverses it again when popping, restoring FIFO order.Final Answer:
Use two stacks to reverse the order twice to maintain queue order -> Option BQuick Check:
Two reversals keep FIFO order [OK]
- Thinking both stacks store elements in sorted order
- Using stacks only for enqueue or dequeue, not both
- Confusing stack order with queue order
x onto a stack named stack1 in C?Solution
Step 1: Recall stack push function in C
In C, stacks are usually implemented with functions like push(stack, element).Step 2: Identify correct argument order
The stack is passed first, then the element to push, so push(stack1, x) is correct.Final Answer:
push(stack1, x); -> Option AQuick Check:
Function call with stack first, element second [OK]
- Using object.method() syntax which is not valid in C
- Swapping argument order in push function
- Assuming push is a built-in method
s1 and s2. What will be the output after the operations?push(s1, 10);
push(s1, 20);
pop(s2);
if (isEmpty(s2)) {
while (!isEmpty(s1)) {
push(s2, top(s1));
pop(s1);
}
}
pop(s2);
printQueue(s1, s2);Solution
Step 1: Push 10 and 20 onto s1
s1 = [10 (bottom), 20 (top)], s2 = []Step 2: Pop from s2 (empty), then transfer all from s1 to s2
Transfer reverses order: s2 = [20 (bottom), 10 (top)], s1 = []Step 3: Pop from s2 removes 10 (top)
s2 = [20]Step 4: printQueue shows elements in queue order
Queue order is s2 top to bottom then s1 bottom to top, so only 20 remains.Final Answer:
Queue elements: 20 -> null -> Option CQuick Check:
First popped element was 10, next is 20 [OK]
- Not transferring elements from s1 to s2 when s2 is empty
- Confusing top and bottom elements during transfer
- Assuming pop removes from s1 directly
s1 and s2. What is the bug?int dequeue() {
if (isEmpty(s2)) {
while (!isEmpty(s1)) {
push(s2, top(s1));
pop(s1);
}
}
return pop(s2);
}Solution
Step 1: Check for empty queue condition
The code does not check if both s1 and s2 are empty before dequeue, which can cause errors.Step 2: Identify missing empty check
Without this check, pop(s2) may be called on empty stack causing runtime error.Final Answer:
Missing check if both stacks are empty before dequeue -> Option AQuick Check:
Empty queue must be handled before popping [OK]
- Assuming pop returns the popped value in C without checking
- Ignoring empty queue condition
- Confusing push direction between stacks
s1 and s2. You perform the following operations:enqueue(1); enqueue(2); dequeue(); enqueue(3); dequeue(); dequeue();
What will be the output sequence of the dequeued elements?
Solution
Step 1: Enqueue 1 and 2
s1 = [1 (bottom), 2 (top)], s2 = []Step 2: Dequeue first element
s2 empty, transfer all from s1 to s2: s2 = [2 (bottom), 1 (top)], s1 = []
Pop from s2 removes 1Step 3: Enqueue 3
Push 3 to s1: s1 = [3], s2 = [2]Step 4: Dequeue second element
s2 not empty, pop from s2 removes 2Step 5: Dequeue third element
s2 empty, transfer s1 to s2: s2 = [3], s1 = []
Pop from s2 removes 3Final Answer:
[1, 2, 3] -> Option DQuick Check:
FIFO order maintained by two stacks [OK]
- Not transferring elements when s2 is empty
- Assuming enqueue adds to s2 instead of s1
- Mixing order of popped elements
Ready to prove it?
Pass the test and this pattern moves unknown
