AlgoMaster Logo

Implement Queue using Stacks

easyFrequency5 min readUpdated June 23, 2026

Understanding the Problem

We need to build a queue (FIFO: first in, first out) using only stacks (LIFO: last in, first out). These two data structures have opposite ordering. When you push elements 1, 2, 3 onto a stack, popping gives you 3, 2, 1. A queue should give you 1, 2, 3 in the same order they went in.

The question is how to reverse the order of elements using stacks. Pushing elements onto one stack and then popping them all into a second stack reverses the order. The element that was at the bottom of the first stack ends up on top of the second stack, which is the element that should come out first in a queue.

What separates the approaches is efficiency, specifically which operation pays the cost of moving elements between stacks. There are two main strategies, and they make opposite choices.

Key Constraints:

  • 1 <= x <= 9 → Values stay small, so there are no overflow concerns and a plain int is enough in every language.
  • At most 100 calls → The volume is low enough that any correct approach passes. The follow-up asking for amortized O(1) is the real design goal.
  • All pop and peek calls are valid → We never have to handle an empty queue for these operations, so the code can skip those guards.

Approach 1: Push-Heavy (Eager Transfer)

Intuition

This approach keeps one stack in queue order at all times so that pop and peek read the oldest element directly off the top. The cost of maintaining that order is paid during push.

We designate one stack as main, where elements are stored in queue order with the oldest on top. When a new element arrives, we move everything from main to a temporary helper stack, push the new element onto the now-empty main, and move everything back. The new element ends up at the bottom of main, and the oldest element returns to the top.

Algorithm

  1. Maintain two stacks: main (stores elements in queue order, oldest on top) and helper (temporary storage during push).
  2. push(x): Move all elements from main to helper. Push x onto main. Move all elements back from helper to main.
  3. pop(): Pop from main (the top is the oldest element).
  4. peek(): Peek at main (the top is the oldest element).
  5. empty(): Check if main is empty.

Example Walkthrough

main
1Initial state: both stacks empty
helper
1Initial state: helper empty
1/7

Code

Every push rearranges the entire queue, so a sequence of pushes does repeated O(n) work. The next approach defers the rearranging until a dequeue needs it.

Approach 2: Pop-Heavy (Lazy Transfer) - Amortized O(1)

Intuition

Instead of doing the reordering work during every push, this approach defers it until a dequeue needs it. It uses two stacks with distinct roles: an input stack for pushing and an output stack for popping.

A push appends the element to the input stack and does nothing else, so it is O(1).

A pop or peek reads from the output stack. If the output stack has elements, its top is the oldest element, so we pop or peek directly. If the output stack is empty, we move every element from the input stack into the output stack first. Popping from input and pushing onto output reverses the order, which puts the oldest element on top of output.

Each element is moved at most twice over its lifetime: once onto the input stack, and once during the transfer to the output stack. Across n operations the total movement is O(n), so each operation is amortized O(1).

Algorithm

  1. Maintain two stacks: input (receives pushed elements) and output (serves pop/peek requests).
  2. push(x): Push x onto the input stack.
  3. pop(): If the output stack is empty, transfer all elements from input to output (this reverses their order). Pop from the output stack.
  4. peek(): If the output stack is empty, transfer all elements from input to output. Return the top of the output stack without removing it.
  5. empty(): Return true only if both stacks are empty.

Example Walkthrough

input
1Initial: both stacks empty
output
1Initial: output empty
1/8

Code