Recursion
A Function That Calls Itself
Imagine standing between two mirrors facing each other. Each mirror reflects the other, and inside each reflection you can see another pair of mirrors reflecting again β seemingly forever. Recursion in programming has the same self-referential quality: a function that calls itself as part of its own definition.
What stops the reflections going on forever in real life? They fade. What stops a recursive function running forever? A base case β a condition that ends the chain of calls and starts returning results back up.
The Two Parts of Every Recursive Function
Every working recursive function has exactly two parts:
- The base case β the simplest possible input, handled directly without another recursive call. This is the exit condition.
- The recursive case β the general situation, which reduces the problem by one step and then calls the function again on that smaller version.
Without the base case, the function calls itself endlessly and the program crashes with a stack overflow error. Without the recursive case, the function never breaks down the problem and never does any real work.
Worked Example β Factorial
The factorial of a positive integer n (written n!) is the product of every integer from 1 up to n:
5! = 5 Γ 4 Γ 3 Γ 2 Γ 1 = 120
Notice the pattern: 5! = 5 Γ 4!. That is, the factorial of n is just n multiplied by the factorial of n β 1. This is a perfect fit for recursion.
FUNCTION factorial(n)
IF n = 1 THEN // base case
RETURN 1
ELSE // recursive case
RETURN n * factorial(n - 1)
ENDIF
ENDFUNCTION
Tracing factorial(4):
factorial(4)
β 4 Γ factorial(3)
β 3 Γ factorial(2)
β 2 Γ factorial(1)
β 1 (base case reached)
β 2 Γ 1 = 2
β 3 Γ 2 = 6
β 4 Γ 6 = 24
Each call pauses, waiting for the next call to return, before it can complete its own multiplication.
The Call Stack
Every time a function is called, the computer adds a stack frame to the call stack β a record of where the program is and what its local variables hold. During recursion, the call stack grows one frame deeper with every recursive call. When the base case returns, the frames are unwound one by one back to the original call.
This is why recursion uses more memory than a simple loop: ten recursive calls mean ten stack frames sitting in memory at once. A very deep recursion (thousands of calls) can exhaust available stack space, producing a stack overflow.
Worked Example β Countdown
A simpler recursive example counts down from any number to zero:
FUNCTION countdown(n)
IF n = 0 THEN
OUTPUT "Go!"
RETURN
ENDIF
OUTPUT n
countdown(n - 1)
ENDFUNCTION
Calling countdown(3) prints:
3
2
1
Go!
Each call outputs its own number, then hands off to the next. When n reaches 0, the base case fires and no further calls are made.
Recursion vs Iteration
Any problem solvable with recursion can also be solved with a loop (iteration), and vice versa. So why use recursion at all?
Some problems have a naturally recursive structure β their solution is defined in terms of a smaller version of itself. The most famous examples include tree traversal, directory searching, and certain sorting algorithms like merge sort. Writing these iteratively requires manually managing a stack in your own code, which is often more complex than simply letting the function call itself.
Recursion is cleaner for problems like these. Iteration is often more efficient for problems that are just repetitive, such as summing a list.
Common Pitfalls
Forgetting the base case is the most frequent mistake. Always ask: "What is the simplest input this function could receive, and can I handle it directly without another call?"
Not moving toward the base case is the other trap. Each recursive call must make progress β the input must get smaller (or simpler) with every call. If n never decreases, the function loops forever.
Key Words
- Recursion β a technique where a function calls itself as part of its definition
- Base case β the simplest input that is handled directly, stopping further calls
- Recursive case β the general situation, which reduces the problem and calls the function again
- Call stack β the memory structure that tracks all active function calls
- Stack frame β a single entry on the call stack, recording one function call's local state
- Stack overflow β the crash that occurs when recursion goes too deep and exhausts available stack memory
- Unwinding β the process of returning results back up through the chain of calls after the base case is reached