Reversing a Stack Using Recursion

To get differentiated do use use a second Stack

Share
Reversing a Stack Using Recursion
Photo by Anne Nygård / Unsplash

Reversing a stack sounds trivial until someone adds the one constraint that makes it interesting: do it without borrowing another data structure. It's a small, elegant problem — and a great way to build intuition for how recursion can quietly stand in for extra memory.
Let's start from the obvious solution and then earn our way to the elegant one.

The Problem

We have a stack, and we want to reverse it. If the stack is [1, 2, 3] (with 3 on top), after reversing it should be [3, 2, 1] (with 1 on top). The top becomes the bottom, and the bottom becomes the top.

The Naive Solution: Use a Second Stack

The first idea most people reach for is to pop everything into an auxiliary stack and push it back:

function reverseStack(st) {    
    let aux = [];
    while (st.length > 0) {      
        let top = st.pop();
        aux.push(top);
    }
   st = aux;
}

let st = [1, 2, 3, 4, 5];
reverseStack(st);
console.log(st);

This works. As we pop from st, the bottom-most element comes out last, so it lands on top of aux — and when we push aux back, the order is reversed.

But there's a catch: we used a whole extra stack. That's O(n) auxiliary space. The interesting version of this problem asks: can we reverse the stack using only the stack itself and the call stack?

That's where recursion comes in.

The Elegant Solution: Recursion

The key insight is that the recursion call stack is our temporary storage. We don't need a visible auxiliary array — we can hold elements "in flight" inside recursive calls.

The trick breaks into two pieces:

  1. A helper that can insert an element at the bottom of a stack.
  2. A reverse function that pops the top, reverses the rest, then pushes the old top all the way to the bottom.

Step 1: Insert at the Bottom

A stack only lets us touch the top. So how do we insert at the bottom? We pop our way down to the bottom recursively, place the element there, and then push everything back on the way out:

function insertAtBottom(st, x) {   
    if (st.length === 0) {       
        st.push(x);       
        return;    }
    let top = st.pop();
    insertAtBottom(st, x);
    st.push(top);
}

let st = [1, 2, 3, 4, 5];
insertAtBottom(st, 6);
console.log(st);

When the stack is empty, we've reached the bottom — so we push x. Every recursive frame is "holding" one element in its top variable, and as the calls unwind, each frame puts its element back on top. The net effect: x sits at the very bottom, and everything else keeps its original order.

Step 2: Reverse Using That Helper

Now reversing is beautifully simple. Pop the top element, reverse everything beneath it, then push that old top to the bottom:

function reverseStack(st) {   
    if (st.length === 0) return;
    let top = st.pop();
    reverseStack(st);
    insertAtBottom(st, top);
}

function insertAtBottom(st, x) {   
    if (st.length === 0) {       
        st.push(x);       
        return;    }
    let top = st.pop();
    insertAtBottom(st, x);
    st.push(top);
}

let st = [1, 2, 3, 4, 5];
reverseStack(st);
console.log(st);

Why It Works

The logic is easier to trust once you say it out loud:

If I move the current top element to the bottom, and I do that for every element from top down, the whole stack flips.

The first element popped (the original top) ends up pushed to the bottom last-ish — actually it gets inserted at the bottom of the fully-reversed remainder, so it lands where the bottom should be. Each element, in turn, gets relocated to the bottom of the growing reversed stack. Recursion just gives us a clean way to process "the top first, then the rest."

Let's trace [1, 2, 3] (top is 3):

  • Pop 3, reverse [1, 2], then insert 3 at bottom.
  • Reversing [1, 2]: pop 2, reverse [1], insert 2 at bottom.
  • Reversing [1]: pop 1, reverse [], insert 1 at bottom → [1].
  • Insert 2 at bottom → [2, 1].
  • Insert 3 at bottom → [3, 2, 1]. ✅

Complexity

There's a cost to elegance here, and it's worth being honest about it:

  • Time: insertAtBottom is O(n), and we call it once per element, so reverseStack is O(n²).
  • Space: O(n) — but it's the recursion call stack, not an explicit data structure.

The two-stack version is O(n) time and O(n) explicit space. So the recursive version trades time for the satisfaction of not allocating a second stack. In an interview, the recursive solution is usually what's being asked for, precisely because it demonstrates that you understand the call stack as a form of storage.

Takeaway

The pattern here — pop the top, recurse on the rest, then do something on the way back up — shows up all over recursion problems. Once "insert at the bottom" clicks, reversing a stack is almost a one-liner of intent. That's the whole charm of this problem: it's tiny, but it rewires how you think about what recursion is really storing for you.