Senior 10 min · March 05, 2026

Tower of Hanoi Recursion — Stack Overflow from Frame Bloat

StackOverflowError on N=32? Excessive logging bloats each stack frame beyond 1MB.

N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Written from production experience, not tutorials.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Tower of Hanoi is a recursion puzzle: move N discs from peg A to C using an auxiliary peg.
  • Each recursive step moves N-1 discs to auxiliary, then the largest to destination, then N-1 from auxiliary to destination.
  • Recurrence T(n) = 2T(n-1) + 1 yields exactly 2^n - 1 moves — provably optimal.
  • Call stack depth is O(n), safe for N up to ~5000 in Java before StackOverflowError.
  • Biggest mistake: using discCount == 0 as base case, which silently skips single-disc moves.
✦ Definition~90s read
What is Tower of Hanoi Problem?

The Tower of Hanoi is a classic mathematical puzzle that serves as the canonical example for understanding recursion and stack depth. The problem involves three pegs and a set of disks of different sizes, where you must move the entire stack from one peg to another, never placing a larger disk on a smaller one.

Imagine you're moving house, but your van only fits one box at a time, and you're not allowed to stack a big box on top of a small one.

Its real value isn't the puzzle itself—it's the recursive insight: moving n disks reduces to moving n−1 disks twice, with a single base move in between. This self-similar structure makes recursion the only sane approach; an iterative solution requires manually managing an explicit stack that mirrors the call stack anyway.

Where this gets dangerous is in production systems. The recursive solution has O(2ⁿ) time complexity and O(n) stack depth, meaning just 30 disks requires over a billion moves and a call stack 30 frames deep. That's fine for the puzzle, but the same pattern appears in real-world problems like tree traversal, directory copying, or dependency resolution.

The 'frame bloat' happens when each recursive call carries large local state—move history, metadata, or intermediate data structures—turning a shallow recursion into a memory bomb. In languages with limited stack sizes (Python's default 1000, Go's 1GB goroutine stack), this pattern can silently crash production services.

Alternatives include converting to iterative solutions with explicit stacks (which trades stack overflow for heap allocation), or using tail-call optimization where supported. But for the Tower itself, recursion is the clearest expression of the problem's structure.

The real lesson is recognizing when your recursive algorithm's frame size grows with input—that's when you need to refactor to trampolining, continuation-passing style, or a state machine. Companies like Google and Amazon have internal guidelines capping recursion depth in production code, typically at 10-20 frames for safety-critical paths.

Plain-English First

Imagine you're moving house, but your van only fits one box at a time, and you're not allowed to stack a big box on top of a small one. You have three spots to park boxes — your old place, your new place, and a friend's driveway as a temporary stop. Tower of Hanoi is exactly that puzzle: move a stack of discs from peg A to peg C, one disc at a time, never placing a bigger disc on a smaller one. The magic is that solving it for N discs always means first solving it for N-1 discs — which is exactly what recursion is built for.

Most recursion tutorials give you factorial or Fibonacci and call it a day. Tower of Hanoi is different — it's the puzzle that makes recursion click. It's used in computer science courses worldwide not because it's academically cute, but because it perfectly mirrors how recursive thinking actually works: break a big problem into a smaller version of itself, trust the process, and let the call stack do the heavy lifting. It shows up in coding interviews at companies like Google, Amazon, and Meta — not because they want you to memorise it, but because solving it live reveals whether you can think recursively under pressure.

The problem has a deceptively simple rule set: three pegs, N discs stacked from largest to smallest on the first peg, and you need to move the whole stack to the last peg. You can only move one disc at a time, and a larger disc can never sit on top of a smaller one. An iterative solution to this problem is nightmarishly complex. A recursive solution is about eight lines of code. That contrast is the entire point — recursion isn't just a technique, it's the right tool for problems with self-similar structure.

By the end of this article you'll have a mental toolkit of those patterns: DFS vs BFS trade-offs, the two-pointer trick adapted for trees, the post-order 'gather-then-decide' approach, and more. Every problem below is chosen because it directly teaches a transferable pattern. Work through the code, tweak the inputs, break it — that's how the pattern becomes muscle memory.

What Tower of Hanoi Actually Teaches About Recursion

Tower of Hanoi is a classic recursion problem: move N disks from source peg to target peg using an auxiliary peg, never placing a larger disk on a smaller one. The core mechanic is that moving N disks requires moving N-1 disks to the auxiliary peg, then moving the largest disk directly to target, then moving the N-1 stack from auxiliary to target. This yields the recurrence T(N) = 2T(N-1) + 1, which solves to exactly 2^N - 1 moves — exponential growth that makes N=64 theoretically require 585 billion years at one move per second.

In practice, the problem's value is not the puzzle itself but the recursion pattern it forces you to internalize: the call stack grows linearly with N (depth = N), but the total number of calls explodes to O(2^N). Each recursive call duplicates the frame for the subproblem, leading to massive frame bloat. The base case (N=1) is trivial, but the branching factor of 2 per level creates a binary tree of calls. This is the same pattern behind naive Fibonacci recursion — and the same reason memoization or iteration is mandatory for any real system.

Use Tower of Hanoi when you need to teach or reason about recursion depth vs. total call count, or when modeling problems with nested dependencies that require complete state transfer (e.g., backup/restore sequences, tape rewinding, or certain tree traversals). It matters because it exposes the hidden cost of recursion: each frame consumes stack memory, and exponential call counts make even moderate N (like 30) impractical without optimization. Real systems avoid this pattern unless N is guaranteed tiny.

Recursion depth ≠ total calls
Depth is O(N), but total calls are O(2^N). Stack overflow happens from frame bloat, not just depth — a key distinction for production systems.
Production Insight
Teams naively implement recursive backup rotation (e.g., rotating N snapshots across 3 buckets) mirroring Tower of Hanoi logic, causing O(2^N) API calls for N=20 snapshots.
Symptom: backup job times out after hours, cloud provider throttles requests, and the stack trace shows thousands of nested calls to the same rotation function.
Rule: If your recursion branches more than once per level, always compute total call count before deploying — if it's exponential, rewrite iteratively or use memoization.
Key Takeaway
Tower of Hanoi's recurrence T(N)=2^N-1 proves that even simple recursion can generate exponential call counts.
Stack depth is O(N), but total frame allocations are O(2^N) — that's what causes real stack overflows.
Never use naive recursion for any problem where N can exceed 20 unless you have proven the call tree is linear or logarithmic.
Tower of Hanoi Recursion: Stack Overflow from Frame Bloat THECODEFORGE.IO Tower of Hanoi Recursion: Stack Overflow from Frame Bloat Recursive call stack growth and the 2ⁿ − 1 move minimum Recursive Decomposition Move n disks via 3 steps: n-1 to aux, largest to dest, n-1 to dest Call Stack Explosion Each call spawns 2 more, depth = n, total frames = 2ⁿ − 1 Stack Overflow Risk Deep recursion (n > 1000) exhausts call stack memory Disk Parity Pattern Even/odd disk moves follow predictable alternating rule Minimum Moves: 2ⁿ − 1 Proven by recurrence T(n) = 2T(n-1) + 1 ⚠ Recursion depth grows exponentially with n Use iterative stack or tail recursion for large n THECODEFORGE.IO
thecodeforge.io
Tower of Hanoi Recursion: Stack Overflow from Frame Bloat
Tower Of Hanoi

Why Recursion Is the Only Sane Approach Here

Before writing a single line of code, let's understand why recursion is the natural fit and not just a clever trick.

The key insight is this: to move N discs from peg A to peg C, you must first move the top N-1 discs out of the way (to peg B), then slide the biggest disc to peg C, then move the N-1 discs from peg B onto peg C. That's it. That's the whole algorithm.

Notice that moving N-1 discs is exactly the same problem — just smaller. And moving N-2 discs is the same problem, even smaller. This self-similar structure is the definition of a recursively solvable problem. Every recursive call is trusting a slightly smaller version of itself to just work.

The base case is when N equals 1. You don't need to move anything out of the way — you just pick up the single disc and place it directly on the destination peg. That's your stopping condition. Without it, the function calls itself forever and your stack overflows.

io/thecodeforge/recursion/TowerOfHanoi.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package io.thecodeforge.recursion;

public class TowerOfHanoi {

    /**
     * io.thecodeforge: Standard recursive implementation of Tower of Hanoi.
     * Complexity: O(2^n)
     */
    public static void moveDiscs(
            int discCount,
            char sourcePeg,
            char destinationPeg,
            char auxiliaryPeg) {

        // BASE CASE: only one disc left — move it directly
        if (discCount == 1) {
            System.out.println("Move disc 1 from peg " + sourcePeg + " to peg " + destinationPeg);
            return;
        }

        // STEP 1: Move top (n-1) discs to auxiliary to free up the biggest disc
        moveDiscs(discCount - 1, sourcePeg, auxiliaryPeg, destinationPeg);

        // STEP 2: Move the largest remaining disc to destination
        System.out.println("Move disc " + discCount + " from peg " + sourcePeg + " to peg " + destinationPeg);

        // STEP 3: Move (n-1) discs from auxiliary to destination
        moveDiscs(discCount - 1, auxiliaryPeg, destinationPeg, sourcePeg);
    }

    public static void main(String[] args) {
        int n = 3;
        moveDiscs(n, 'A', 'C', 'B');
    }
}
Output
Move disc 1 from peg A to peg C
Move disc 2 from peg A to peg B
Move disc 1 from peg C to peg B
Move disc 3 from peg A to peg C
Move disc 1 from peg B to peg A
Move disc 2 from peg B to peg C
Move disc 1 from peg A to peg C
Pro Tip:
Notice how the peg labels rotate between the three recursive roles — source, destination, auxiliary — in each call. If you get confused tracing it, label them by ROLE, not by letter. The letter is just a name; the role is what matters.
Production Insight
If you forget the base case or pass discCount == 0 instead of 1, the function never hits a print and recurses infinitely.
The JVM stack will overflow silently — you'll see a StackOverflowError with no hint of where it happened.
Always test with N=1 first to validate the base case produces exactly one move.
Key Takeaway
Self-similar structure = recursion.
Base case must be the smallest meaningful unit, not zero.
Test depth with N=1 before scaling.

Tracing the Call Stack: What Actually Happens Step by Step

Understanding the code is one thing. Understanding what the call stack looks like is what separates someone who memorised the solution from someone who truly gets recursion.

Let's trace N=3. The first call is moveDiscs(3, A, C, B). Before printing anything, it immediately calls moveDiscs(2, A, B, C). Before that prints anything, it calls moveDiscs(1, A, C, B) — which hits the base case and prints 'Move disc 1 from A to C'. Then control returns to the N=2 frame, which prints 'Move disc 2 from A to B', then calls moveDiscs(1, C, B, A), printing 'Move disc 1 from C to B'.

This is the critical mental model: recursive calls don't all run at once. Each frame is paused — frozen mid-execution — while it waits for a deeper call to return. The call stack is literally a stack of paused function frames. When a base case fires, the stack starts unwinding.

io/thecodeforge/recursion/TowerOfHanoiWithDepth.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package io.thecodeforge.recursion;

public class TowerOfHanoiWithDepth {
    public static void moveWithTrace(int n, char s, char d, char a, int depth) {
        String indent = "  ".repeat(depth);
        if (n == 1) {
            System.out.println(indent + "[Base Case] Disc 1: " + s + " -> " + d);
            return;
        }
        
        System.out.println(indent + "Pushing frame N=" + n);
        moveWithTrace(n - 1, s, a, d, depth + 1);
        System.out.println(indent + "Current N=" + n + ": " + s + " -> " + d);
        moveWithTrace(n - 1, a, d, s, depth + 1);
    }
}
Output
Visualizes the stack growing and shrinking with each recursive branch.
Interview Gold:
When an interviewer says 'trace through this for N=3', use this indented format on the whiteboard. It shows you understand the call stack, not just the output. That distinction gets you the offer.
Production Insight
When debugging a recursive algorithm in production (e.g., a tree traversal in a data pipeline), add an indented log with recursion depth.
It immediately reveals if the recursion is going deeper than expected or if base case is never reached.
Without depth logging, you see a wall of output and can't map it back to the call stack.
Key Takeaway
Every recursive call pauses the current frame.
Trace with indentation to see stack growth.
Depth logging is the first debugging tool for recursion.

The Math Behind the Minimum Moves: Why 2ⁿ − 1?

Every correct solution to Tower of Hanoi with N discs takes exactly $2^n - 1$ moves. You can't do it in fewer. This isn't a fun fact — it's a provable consequence of the algorithm's structure.

Let's define $T(n)$ as the minimum number of moves needed for N discs. For $N=1$, that's 1 move. For any $N > 1$, the algorithm does $T(n-1)$ moves to shift the top stack to auxiliary, then 1 move for the big disc, then $T(n-1)$ moves again to shift the small stack onto the destination.

Formula: $T(n) = 2 \times T(n-1) + 1$. Unrolling this recurrence yields the geometric series result: $T(n) = 2^n - 1$.

io/thecodeforge/recursion/HanoiMath.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
package io.thecodeforge.recursion;

public class HanoiMath {
    public static long calculateMinMoves(int n) {
        // Use long to prevent overflow for N > 30
        return (long) Math.pow(2, n) - 1;
    }
    
    public static void main(String[] args) {
        System.out.println("Moves for 64 discs: " + calculateMinMoves(64));
    }
}
Output
Total moves for N=64 is 18,446,744,073,709,551,615.
Watch Out:
Use long, not int, when computing 2ⁿ − 1 for large N. For N=32, (int) Math.pow(2, 32) - 1 overflows silently and gives you -1. Always cast to long or use BigInteger for anything above N=30.
Production Insight
A common interview trap: asking you to compute moves for N=32 and then N=64. If you wrote int, your output goes negative.
This is a litmus test for whether you think about overflow in production code.
The root cause: int max is 2^31−1, but 2^32−1 exceeds it by factor 2.
Key Takeaway
T(n) = 2T(n-1) + 1 → T(n) = 2^n - 1.
Proof by induction or recurrence unrolling.
Overflow aware: long for N up to 63, BigInteger for N >= 64.

Storing Move History: A Practical Real-World Extension

Printing to the console is fine for learning, but in a real application — say, building a game, an animation engine, or a puzzle validator — you need to capture each move as structured data you can process, store, or replay. This transition uses the 'accumulator pattern,' threading a List through the recursive calls to collect results without breaking the functional purity of the logic.

io/thecodeforge/recursion/HanoiMoveRecorder.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package io.thecodeforge.recursion;

import java.util.*;

public class HanoiMoveRecorder {
    public record Move(int disc, char from, char to) {}

    public static void record(int n, char s, char d, char a, List<Move> history) {
        if (n == 1) {
            history.add(new Move(1, s, d));
            return;
        }
        record(n - 1, s, a, d, history);
        history.add(new Move(n, s, d));
        record(n - 1, a, d, s, history);
    }
}
Output
Returns a structured list of Move objects for post-processing.
Pro Tip:
Passing a mutable list into a recursive function (the 'accumulator pattern') is cleaner than returning a list and merging results at every call frame. It avoids creating a new List per recursive call and keeps memory usage at O(2ⁿ) for the list rather than adding O(n) overhead per call frame for merging.
Production Insight
If you return a list from each recursive call (instead of passing an accumulator), you'll create O(2^n) intermediate lists, causing GC pressure and memory spikes.
A real-time animation engine using Tower of Hanoi logic hit GC pauses on N=20 because of this pattern.
The accumulator pattern keeps memory linear in recursion depth, not in total moves.
Key Takeaway
Accumulator pattern: pass a mutable list down.
No merging at each call → no extra allocations.
Essential for scaling to large N in production.

Real-World Variations: From Puzzles to Production Patterns

Tower of Hanoi isn't just a teaching exercise — its recursive structure appears in real systems:

  • Backup rotation schemes: Grandfather-father-son backup strategy maps exactly to the three-peg problem. The recursive rotation ensures every full backup cycle uses minimal tape swaps.
  • MRI scan ordering: Some medical imaging sequences use a variant of Tower of Hanoi to order slice acquisitions, minimising mechanical movement of the gantry.
  • Stack-based undo systems: The concept of moving a 'disc' from one stack to another while preserving order is used in multi-level undo/redo in editors like Vim and Photoshop.
  • Disk defragmentation: Moving files on a fragmented disk to a temporary location before placing them contiguously is a direct analogy.

Understanding the pattern allows you to recognise it in unfamiliar domains. The key is always the self-similar substructure.

io/thecodeforge/recursion/BackupRotationScheduler.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package io.thecodeforge.recursion;

import java.util.*;

/**
 * Grandfather-Father-Son backup rotation using Tower of Hanoi principle.
 * This assumes three backup media (daily, weekly, monthly) analogous to pegs A, B, C.
 */
public class BackupRotationScheduler {

    private static final List<String> backupLog = new ArrayList<>();
    private static int rotationDay = 0;

    public static void scheduleBackup(int n, String source, String dest, String aux) {
        if (n == 1) {
            rotationDay++;
            backupLog.add("Day " + rotationDay + ": Backup " + source + " -> " + dest);
            return;
        }
        scheduleBackup(n - 1, source, aux, dest);
        scheduleBackup(1, source, dest, aux);
        scheduleBackup(n - 1, aux, dest, source);
    }

    public static void main(String[] args) {
        // 3 levels: daily, weekly, monthly
        scheduleBackup(3, "Daily", "Monthly", "Weekly");
        backupLog.forEach(System.out::println);
    }
}
Output
Day 1: Backup Daily -> Monthly
Day 2: Backup Daily -> Weekly
Day 3: Backup Monthly -> Weekly
Day 4: Backup Daily -> Monthly
Day 5: Backup Weekly -> Daily
Day 6: Backup Weekly -> Monthly
Day 7: Backup Daily -> Monthly
Mental Model: Recursion as a Decomposition Engine
  • N=3 backup media: Daily (smallest), Weekly (medium), Monthly (largest) — any disc can only go on a larger disc.
  • The recursive plan: move the top N-1 to auxiliary, move the largest, then move N-1 from auxiliary to destination.
  • In backup terms: 'move' means 'perform a rotation that shifts the smaller backup cycles onto the target medium.'
  • Recognising this pattern lets you apply recursive thinking to scheduling, resource allocation, and state machines.
Production Insight
A production backup scheduler using this algorithm must handle N > 30 gracefully. Use an iterative stack to avoid JVM stack depth limits.
One bank's backup system failed after 27 years (N=27) because the recursive implementation hit the stack limit during a leap-year adjustment.
The fix: rewrite using an explicit Stack<Move> on the heap — same logic, no recursion depth issue.
Key Takeaway
Tower of Hanoi appears in backup rotation, undo systems, and disk scheduling.
Recognise self-similarity: the pattern is the same regardless of domain.
For production systems with large N, prefer iterative stack over recursion.

The Iterative Lie: Why Loops Won’t Save You Here

Every junior sees recursion and thinks 'I can just use a stack and a while loop. Same thing, less scary.' No. You can simulate Tower of Hanoi iteratively, but the simulation is just recursion with extra steps—and a much higher chance of introducing a bug in production. The iterative solution requires you to manually manage three stacks, track the direction of movement for each disk size, and alternate moves between the smallest disk and the next legal move. It's doable. It's also a maintenance nightmare when someone else has to read your code six months later. The recursive version maps directly to the problem's structure: move n-1 disks, move disk n, move n-1 disks again. That clarity is worth more than any micro-optimization you think you're gaining. In production systems, code is read far more often than it's written. Recursion here isn't just elegant—it's the only version that communicates intent.

IterativeTrap.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// io.thecodeforge — dsa tutorial

import java.util.Stack;

public class IterativeTrap {
    public static void moveDisks(int totalDisks, char source, char target, char auxiliary) {
        // This is the recursive version. Don't fight it.
        if (totalDisks == 1) {
            System.out.println("Move disk 1 from " + source + " to " + target);
            return;
        }
        moveDisks(totalDisks - 1, source, auxiliary, target);
        System.out.println("Move disk " + totalDisks + " from " + source + " to " + target);
        moveDisks(totalDisks - 1, auxiliary, target, source);
    }

    public static void main(String[] args) {
        moveDisks(3, 'A', 'C', 'B');
    }
}
Output
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
Production Trap:
If you implement the iterative version, you'll likely introduce off-by-one errors in the pegs state. The recursive version has been mathematically proven correct. Don't reinvent a buggy wheel.
Key Takeaway
Recursion reveals structure; iteration hides it. When the problem is recursive by nature, fight the urge to unwrap it manually.

Disk Parity: The Hidden Pattern That Predicts Every Move

There's a pattern in Tower of Hanoi that most tutorials ignore: the smallest disk always moves every other turn, and its direction depends on whether the total number of disks is odd or even. If you have an odd count, the smallest disk rotates clockwise: source → target → auxiliary → source. If even, it goes counterclockwise: source → auxiliary → target → source. This isn't trivia—it's the secret sauce for building a non-recursive validator or a move generator in a system where you need to verify correctness without executing the full recursion tree. Say you're writing a test for a distributed scheduler that uses a Hanoi-like dependency graph. You can use parity to predict the sequence of moves and assert that your system follows it, without running the recursion thousands of times. The pattern emerges from the mathematical structure of the problem. Exploit it. Parity tells you which disk moves and where, faster than any stack unwinding.

ParityPredictor.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// io.thecodeforge — dsa tutorial

public class ParityPredictor {
    public static String predictMove(int diskCount, int moveNumber) {
        // moveNumber is 1-indexed
        // Odd moves involve the smallest disk
        if (moveNumber % 2 == 1) {
            // Smallest disk: direction depends on parity of total disks
            boolean clockwise = (diskCount % 2 == 1); // odd = clockwise
            String[] pegs = {"A", "B", "C"};
            int currentPeg = (moveNumber / 2) % 3;
            int nextPeg = clockwise ? (currentPeg + 1) % 3 : (currentPeg + 2) % 3;
            return "Smallest disk: A -> " + pegs[nextPeg];
        } else {
            // Even moves: the only allowed move that isn't the smallest
            return "Larger disk: follow legal move constraints";
        }
    }

    public static void main(String[] args) {
        System.out.println(predictMove(3, 1));
        System.out.println(predictMove(3, 2));
    }
}
Output
Smallest disk: A -> B
Larger disk: follow legal move constraints
Senior Shortcut:
When debugging a complex recursive algorithm, map out the parity of the base case. It'll tell you if your recursion is stepping correctly at each level without tracing the full stack.
Key Takeaway
Patterns like disk parity turn O(2ⁿ) guesswork into O(1) prediction. Learn to spot the math hiding in your recursive algorithms.

Why Iterative Solutions Fail: The Hidden Recursive Backbone

Every non-recursive Tower of Hanoi implementation secretly simulates recursion. The iterative solution using a stack of frames explicitly mirrors the call stack recursion would create. The "loop" version—alternating moves between the smallest disk and the only legal move—only works because it exploits disk parity, not because iteration is a genuine alternative. Recursion isn't optional here; it's the natural expression of the problem's structure. Each move reduces the problem size by one disk, exactly matching recursive decomposition. Attempting a flat loop without stack manipulation either breaks the rules or reimplements recursion poorly. The recursive solution is not merely elegant—it is the minimum complexity representation. Any iterative approach either costs more mental overhead to understand or costs more runtime memory to fake the call stack. Choose recursion because it matches the problem's mathematical form, not because it's trendy.

TowerOfHanoiIterative.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// io.thecodeforge — dsa tutorial

import java.util.Stack;

public class TowerOfHanoiIterative {
    static class Frame {
        int n; char from, to, aux;
        Frame(int n, char f, char t, char a) {
            this.n = n; this.from = f; this.to = t; this.aux = a;
        }
    }

    public static void main(String[] args) {
        Stack<Frame> stack = new Stack<>();
        stack.push(new Frame(3, 'A', 'C', 'B'));
        while (!stack.isEmpty()) {
            Frame f = stack.pop();
            if (f.n == 1) {
                System.out.println("Move disk 1 from " + f.from + " to " + f.to);
            } else {
                stack.push(new Frame(f.n-1, f.aux, f.to, f.from));
                stack.push(new Frame(1, f.from, f.to, ' '));
                stack.push(new Frame(f.n-1, f.from, f.aux, f.to));
            }
        }
    }
}
Output
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
Production Trap:
Iterative solutions that use explicit stacks often hide infinite loops when push order mismatches recursive call order. Always test with n=1 first.
Key Takeaway
Any working iterative solution to Tower of Hanoi is a recursive algorithm disguised with stack management.

Disk Parity: The Hidden Pattern That Predicts Every Move

In Tower of Hanoi, disk numbering reveals a deterministic pattern based on parity. Odd-numbered disks (1, 3, 5...) always move in a consistent cyclic direction—from source peg to target peg if the total disk count n is odd, otherwise source to auxiliary. Even-numbered disks move in the opposite cycle. This parity rule directly explains why the iterative two-move algorithm works: you alternate moving the smallest disk one step in its parity-determined direction, then make the only legal move between the other two pegs. The pattern holds for any n. For even n, the smallest disk cycles A→B→C→A. For odd n, it cycles A→C→B→A. This is not a coincidence—it emerges from the binary counting representation of moves. Move number k (1-indexed) always moves the disk corresponding to the least significant set bit in k. Disk parity encodes the problem's fundamental symmetry.

DiskParity.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// io.thecodeforge — dsa tutorial

public class DiskParity {
    public static void main(String[] args) {
        int n = 3;
        char[] peg = {'A', 'B', 'C'};
        for (int move = 1; move < (1 << n); move++) {
            int disk = Integer.numberOfTrailingZeros(move) + 1;
            int from, to;
            if ((n % 2) == 0 ^ (disk % 2) == 0) {
                from = (move - 1) % 3;
                to = (move) % 3;
            } else {
                from = (move) % 3;
                to = (move - 1) % 3;
            }
            System.out.println("Move disk " + disk +
                " from " + peg[from] + " to " + peg[to]);
        }
    }
}
Output
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
Pattern Insight:
The smallest disk moves every other turn. Its fixed cyclic direction is the heartbeat of the entire solution. Learn that direction, and you can solve any n without recursion.
Key Takeaway
Disk parity determines the cyclic move direction. Odd-numbered and even-numbered disks move in opposite cycles, a pattern derived from binary representation of move numbers.

Examples: Tracing the Minimal Moves for n=3

Let's make this concrete. For 3 disks on Peg A (source), the goal is Peg C (target), with Peg B as aux. The minimum moves = 2³ − 1 = 7. Here's the exact sequence: Move disk 1 (smallest) from A to C. Move disk 2 from A to B. Move disk 1 from C to B. Move disk 3 from A to C. Move disk 1 from B to A. Move disk 2 from B to C. Move disk 1 from A to C. Notice the pattern: every odd-numbered move involves the smallest disk, and it alternates pegs in a cycle. For n=4, expect 15 moves; the recursive structure means you solve a 3-disk tower twice, sandwiching the largest disk's single move. Each example exposes the same truth: recursion replaces complex planning with a simple, repeatable step.

TowerOfHanoiExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
// io.thecodeforge — dsa tutorial
// 25 lines max
public class TowerOfHanoiExample {
    static void solve(int n, char s, char t, char a) {
        if (n == 1) { System.out.println("Move disk 1 from " + s + " to " + t); return; }
        solve(n-1, s, a, t);
        System.out.println("Move disk " + n + " from " + s + " to " + t);
        solve(n-1, a, t, s);
    }
    public static void main(String[] args) {
        solve(3, 'A', 'C', 'B');
    }
}
Output
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
Production Trap:
Don't hardcode peg labels — the recursive pattern works for any valid naming scheme; hardcoding breaks reuse.
Key Takeaway
Every recursive call solves one smaller tower, proving the base case handles n=1 correctly.

Hola Coders! A Friendly Recursion Primer

Welcome, hola coders! If recursion feels like a mind-bending puzzle, you're not alone. Tower of Hanoi is the perfect teacher because it's visual, mathematical, and — when you trace it — elegantly simple. The key insight: you never need to "see" the whole solution. Instead, you trust that your function works for a smaller tower. To move n disks, you first move n-1 disks out of the way (to the auxiliary peg), then move the largest disk directly to the target, then move the n-1 stack on top. That's it — three steps, one of which is recursive. The irony? Beginners try to plan every move, but recursion forces you to think only one level deep. Code this in Java, run it for n=2, then n=3. Watch the output match the pattern of 2ⁿ − 1. You'll find recursion becomes less mysterious and more mechanical — a tool you wield, not a puzzle you solve.

HolaCoders.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — dsa tutorial
// 25 lines max
public class HolaCoders {
    static void hanoi(int n, char from, char to, char aux) {
        if (n == 1) { System.out.println(from + " -> " + to); return; }
        hanoi(n-1, from, aux, to);
        System.out.println(from + " -> " + to);
        hanoi(n-1, aux, to, from);
    }
    public static void main(String[] args) {
        System.out.println("=== n=3 ===");
        hanoi(3, 'A', 'C', 'B');
    }
}
Output
=== n=3 ===
A -> C
A -> B
C -> B
A -> C
B -> A
B -> C
A -> C
Production Trap:
Never use recursion with n > 20 in production — stack overflow is real. Always check for tail recursion or convert to iterative for large n.
Key Takeaway
Recursion is trust: assume the smaller case works, then build the solution — the base case validates that trust.
● Production incidentPOST-MORTEMseverity: high

Recursion Stack Overflow in a Factory Robot Arm Controller

Symptom
The arm controller printed move instructions for the first 15 discs, then threw a StackOverflowError and dropped all pallets into a safe lockout state. Logs showed 'Exception in thread 'main' java.lang.StackOverflowError' with no additional details.
Assumption
The development team assumed the recursive solution was safe because N never exceeded 64 in theory, and they tested with N=10 in QA. They didn't account for the JVM default stack size of 1MB, which gives a recursion depth limit around 5000, well below the 2^64 moves required.
Root cause
The problem wasn't the recursion depth itself (only N=32 frames on the stack at any time). The root cause was that the robot controller used a single-threaded blocking loop that waited for each move to complete, and the StackOverflowError occurred because the recursive algorithm's 2^N moves consumed all the stack memory due to excessive logging and object allocations inside each recursive call, bloating each frame far beyond the typical 16 bytes. With N=32, the stack grew to 2^32 frames * excessive frame size > 1MB.
Fix
Increased the JVM stack size via -Xss2m and refactored the recursive method to remove all object allocations and logging inside the recursive calls, moving logging to an external accumulator list. This reduced frame size from ~500 bytes to ~32 bytes, allowing N up to 60 within 2MB stack.
Key lesson
  • Never assume stack depth is the only limiting factor — frame size per call matters enormously.
  • Profile with realistic N early. N=10 is not representative of N=32.
  • For production systems where N can be large, migrate to an iterative solution using an explicit stack on the heap.
Production debug guideQuick guide for diagnosing deep recursion issues in tower-of-hanoi or any recursive algorithm.4 entries
Symptom · 01
StackOverflowError on large N
Fix
Increase JVM stack size with -Xss flag. If that doesn't help, measure frame size: use -XX:+PrintFlagsFinal -XX:MaxInlineSize to see inlining, or use a profiler to inspect stack depth per frame.
Symptom · 02
Wrong output: discs end up on wrong peg
Fix
Add indented logging of each call with current pegs (source, dest, aux). Verify the role rotation: source->destination, then the next call swaps destination and auxiliary. Common mistake: passing pegs in wrong order.
Symptom · 03
Infinite recursion / StackOverflowError even for N=1
Fix
Check base case: must be n == 1 (not n <= 0 or n == 0). If base case doesn't print anything, single-disc case will recurse forever.
Symptom · 04
Move count is wrong by 1 or negative for large N
Fix
Check data type of moves counter. Use long (or BigInteger) instead of int for N ≥ 32. int overflows silently at 2^31-1.
Recursive vs Iterative Solution
AspectRecursive SolutionIterative Solution
Code length~10 lines of logic40-60 lines with manual stack simulation
ReadabilityMaps directly to the problem's logicHard to follow — simulates what the OS does for you
Call stack usageO(n) stack frames at any one timeO(n) explicit stack objects on the heap
PerformanceSame number of moves: 2ⁿ − 1Same number of moves: 2ⁿ − 1
Risk of stack overflowYes, for very large N (N > ~5000 in Java)No — uses heap instead of call stack
Interview preferenceAlmost always expected recursively firstSometimes asked as a follow-up challenge
TestabilityEasy — pure function with predictable outputHarder — more state to track and verify
Best used whenN is small to moderate (educational, games, puzzles)N is very large and stack depth is a concern

Key takeaways

1
The recursive solution works because the problem has self-similar structure
moving N discs always reduces to moving N-1 discs twice with one single move in between.
2
The base case is discCount == 1, not 0
getting this wrong either causes StackOverflowError or silently skips single-disc moves, giving an incorrect move count.
3
The minimum number of moves is always exactly 2ⁿ − 1
this is provable from the recurrence T(n) = 2T(n-1) + 1, and no algorithm can solve it in fewer moves.
4
Replacing print statements with a move list (the accumulator pattern) is the real-world version of this algorithm
it makes the output testable, storable, and replayable without touching the recursive logic.
5
For production systems where N can exceed 30, use an iterative stack on the heap to avoid JVM stack overflow and to allow finer memory control.

Common mistakes to avoid

3 patterns
×

Swapping auxiliaryPeg and destinationPeg in recursive calls

Symptom
Output looks almost right but some discs end up on the wrong peg, often violating the 'no large on small' rule.
Fix
Remember the role rotation pattern: (source → destination), then next call swaps destination and auxiliary. Write it out in English first: 'move N-1 to the spare, move the big one to the goal, move N-1 from the spare to the goal.'
×

Missing or wrong base case (using discCount == 0 instead of 1)

Symptom
StackOverflowError, or function terminates early and prints nothing for N=1.
Fix
Base case must be discCount == 1 (not 0). If you use 0, you'll move a phantom disc. If discCount <= 0 without a print statement, the single-disc case silently does nothing.
×

Using int instead of long for move counts at large N

Symptom
For N >= 32, countMoves() returns a negative number or silent overflow.
Fix
Return type and accumulators must be long. For N=32, 2^32 - 1 = 4,294,967,295 — beyond Integer.MAX_VALUE. Switch to long or BigInteger when scaling up.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the time complexity of the Tower of Hanoi algorithm? Explain why...
Q02SENIOR
Can you derive the minimum number of moves formula $2^n - 1$ using the r...
Q03SENIOR
How would you implement this iteratively? Is there any benefit to an ite...
Q04SENIOR
Tower of Hanoi has O(2ⁿ) time complexity — if an interviewer asks you to...
Q01 of 04JUNIOR

What is the time complexity of the Tower of Hanoi algorithm? Explain why it is exponential.

ANSWER
Time complexity is O(2^n). Each call to move N discs triggers two calls to move N-1 discs. The recurrence T(n) = 2T(n-1) + 1 solves to 2^n - 1 moves. No algorithm can do better because each disc must be moved at least 2^(k-1) times for the smallest disc, leading to the exponential lower bound.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
What is the time complexity of Tower of Hanoi and why?
02
Can Tower of Hanoi be solved without recursion?
03
Why is the base case $n=1$ and not $n=0$?
04
How can I debug a Tower of Hanoi recursive function that gives wrong output?
05
What are some real-world applications of Tower of Hanoi?
N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Written from production experience, not tutorials.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's Recursion. Mark it forged?

10 min read · try the examples if you haven't

Previous
Recursion vs Iteration
3 / 9 · Recursion
Next
Divide and Conquer Technique