Skip to content
dsa450for five year olds

Stacks & Queues · 15 of 38

Sort a Stack using recursion

Sort a pile of numbered blocks so the biggest is on top, using only the pile and helpers who can each hold one block.

Simple way
time O(n log n)
room O(n)
Clever way
time O(n^2)
room O(n)

The problem, simply

You get a stack of numbers. Sort it so the smallest number is at the bottom and the biggest is on top. You may only use stack moves (push, pop, peek, isEmpty) and recursion. No loops over other arrays, no second stack, no list.

Some versions ask for the smallest on top instead. The method is the same; you only flip one comparison.

A story to remember it

Picture it

stackbefore
34331989223top
stackafter
32331349298top

Before: mixed up. After: smallest at the bottom and biggest on top, using only the stack and recursion.

  • looking now
  • answer

Examples

Six numbers

In
bottom [34, 3, 31, 98, 92, 23] top
Out
bottom [3, 23, 31, 34, 92, 98] top

98 is the biggest, so it ends on top.

The animation's stack

In
bottom [3, 1, 4, 2] top
Out
bottom [1, 2, 3, 4] top

Every number slides down until the number below it is not bigger.

Upside down already

In
bottom [3, 2, 1] top
Out
bottom [1, 2, 3] top

The worst case: every insert has to lift everything that is already sorted.

Repeats and negatives

In
bottom [5, -2, 5, 0] top
Out
bottom [-2, 0, 5, 5] top

Equal numbers sit next to each other. Negative numbers sort like any others.

One number or none

In
bottom [7] top and an empty stack
Out
bottom [7] top and an empty stack

Already sorted.

Way 1: the simple way

If you were allowed a list, you would pour the stack into it, sort the list, and pour it back.

  1. Pop everything into a list.
  2. Sort the list from small to big.
  3. Push the list from the smallest to the biggest. The biggest is pushed last, so it ends on top.
arraylist, sorted
01234532331349298next
stackstack (empty for now)
empty

Way 1 pours the stack into a list, sorts the list, and pushes it back from smallest to biggest.

  • looking now
java
import java.util.*;

class Solution {
    public void sort(Deque<Integer> stack) {
        List<Integer> all = new ArrayList<>();
        while (!stack.isEmpty()) all.add(stack.pop());
        Collections.sort(all);                         // small to big
        for (int x : all) stack.push(x);               // the biggest is pushed last, so it is on top
    }
}

How long it takes: sorting is O(n log n). Extra room: the list, O(n). It is faster, but it breaks the rule about other structures.

Way 2: the clever way

Two recursive functions, just like reversing a stack.

sortedInsert(x) puts x into an already sorted stack:

  1. If the stack is empty, or the top is not bigger than x, push x. Done.
  2. Otherwise pop the top and hold it, call sortedInsert(x) again, then push the held number back.

sort() sorts the whole stack:

  1. If the stack is empty, stop.
  2. Pop the top and hold it, call sort() on the rest, then sortedInsert(held).

Pop everything, then drop each number into its place

01 / 13

stackthe stack (bottom ... top)
3142top
stackcall stack
empty

The stack holds 3, 1, 4, 2 from the bottom, with 2 on top. Goal: smallest at the bottom, biggest on top.

  • looking now
  • checking
  • done
  • answer
  • path
  • just added
java
import java.util.*;

class Solution {
    public void sort(Deque<Integer> stack) {
        if (stack.isEmpty()) return;
        int top = stack.pop();            // hold one number
        sort(stack);                      // sort the rest
        sortedInsert(stack, top);         // drop the held number into its place
    }

    private void sortedInsert(Deque<Integer> stack, int x) {
        if (stack.isEmpty() || stack.peek() <= x) {
            stack.push(x);                // the top is not bigger: x belongs here
            return;
        }
        int held = stack.pop();           // a bigger number is in the way, lift it
        sortedInsert(stack, x);
        stack.push(held);                 // put it back on top
    }
}

How long it takes: there are n inserts and each one may lift every number already sorted, so the total is up to 0 + 1 + ... + (n - 1), which is O(n^2). This is insertion sort, done with the call stack. Extra room: at most about n waiting calls, O(n).

For smallest on top, change stack.peek() <= x to stack.peek() >= x.

Another way: one helper stack, no recursion

A common follow up: sort with one extra stack and loops. Keep the helper sorted with the smallest on top. Pop a number x from the input. While the helper's top is smaller than x, move those numbers back to the input. Then push x onto the helper. At the end, pour the helper back: the smallest goes in first, so the biggest ends on top.

java
import java.util.*;

class Solution {
    public void sort(Deque<Integer> stack) {
        Deque<Integer> helper = new ArrayDeque<>();      // kept with the smallest on top
        while (!stack.isEmpty()) {
            int x = stack.pop();
            while (!helper.isEmpty() && helper.peek() < x) {
                stack.push(helper.pop());                // smaller ones step back into the input
            }
            helper.push(x);
        }
        while (!helper.isEmpty()) stack.push(helper.pop());  // smallest in first, biggest ends on top
    }
}

Numbers that step back into the input get popped again later, so this is also O(n^2) time in the worst case, with O(n) room for the helper.

Watch out for

  • Using < instead of <= in sortedInsert. It still sorts, but equal numbers get lifted for no reason.
  • Forgetting the empty check before peek(). ArrayDeque.peek() returns null on an empty stack, and comparing null with an int throws.
  • Deep recursion. A stack of 100,000 numbers means 100,000 waiting calls and a likely StackOverflowError.

What interviewers ask next

  • Why is it O(n^2) and not O(n)? Each insert can lift all the numbers already sorted, like insertion sort on a reversed list.
  • Reverse a stack with recursion. Same shape, but insert at the bottom instead of in sorted order.
  • Sort a stack with no recursion and only one extra stack. That is the "Another way" above.
  • Can a stack be sorted faster? Any sort that only compares pairs needs O(n log n) comparisons. With two helper stacks you can do a merge sort in O(n log n); with only the call stack or one helper, the simple methods above are O(n^2).

Remember this

Grown-up words: the tower is a stack, the helpers are frames on the call stack, sortedInsert is the insert step of insertion sort, and "no other structure" means no auxiliary data structure.