Data structures & algorithms · Foundations
Recursion & the call stack
Two questions build any recursive function. This page traces factorial(4) frame by frame, so you watch the stack grow on the way down and hand the answer back on the way up.
Push and pop the stack yourself →01 The idea
A function that calls itself, and a stack that remembers
Some problems are defined in terms of themselves. Four factorial is four times three factorial. The size of a folder is the size of everything inside it, and the things inside it are folders. When the definition points back at itself, the code can too: the function calls itself on a smaller input and uses whatever comes back.
What makes that work is not magic. Every call that has not finished yet is parked in a box called a stack frame, and the runtime keeps those boxes stacked in order until the answers arrive.
02 Hand trace
factorial(4), one frame at a time
Take factorial(4), defined the way a maths book defines it: 4! = 4 × 3!. Each box below is one stack frame, and the newest frame sits at the right-hand end. Follow n down and the returned value back up. A rose note means that frame still owes an answer; a green note means it has one.
Read the two halves separately. The top four rows are the descent: four frames created and not one multiplication done. The first three park mid-expression; the fourth, n = 1, is the base case, so it answers outright and turns the run around. The bottom three rows are the unwind, and that is where all three multiplications happen, in the reverse order of the calls. One more pop — factorial(4) itself — empties the stack, and 24 is the answer. Most students follow the descent and lose the unwind, and the unwind is where the answer is actually built.
03 Code
The two-question method, written down
The trace showed a shape you can now write as code. Every recursive function is the same two-part answer to the two questions from section 01, and getting either part slightly wrong is exactly how a stack fills up.
Broken · no base case
function factorial(n): return n * factorial(n - 1) # nothing stops it # 4 -> 3 -> 2 -> 1 -> 0 -> -1 -> -2 ...# frames pile up until the stack overflows
Correct · base case first
function factorial(n): if n <= 1: # 1 · base case return 1 return n * factorial(n - 1) # 2 · recursive case# factorial(4) = 24, four frames deep
The base case goes first. The left version has no stopping condition, so factorial(4) calls 3, then 2, then 1, then 0, then −1, and keeps going. Nothing returns, so nothing pops, and the runtime raises a stack overflow once the frames fill the stack.
Write n <= 1, not n == 1. The <= form catches 0 as well as 1. With n == 1, a call to factorial(0) slides straight past the check and heads off toward −1. A base case that some inputs step over is the same bug as having no base case at all.
The multiply is what the frame is holding. n * factorial(n - 1) cannot be computed when the call is made, because the right-hand side is not a number yet. The frame stores n and parks at the multiply. That parked multiply is why the answer is assembled on the way back up, and why n frames of memory are the price of writing it this way.
05 Cheat sheet
What gets asked about recursion
| Recursion shape | Calls for input n | Deepest stack |
|---|---|---|
| Linear · one call per level (factorial) | O(n) | O(n) |
| Tree · two calls per level (naive fib) | O(2ⁿ) | O(n) |
| Halving · one call on half the input | O(log n) | O(log n) |
| Base case unreachable | never ends | overflows |
06 Where & why
When recursion earns its frames
Recursion is not faster than a loop. It costs a frame per pending call and it can overflow where a loop cannot. What you buy is code shaped like the data, and on self-similar data that shape removes most of the bookkeeping bugs.
Reach for it when…
Use something else when…
| Situation | Better choice | Why |
|---|---|---|
| Depth grows with the input — a linked list of 100,000 nodes | A loop, or your own stack on the heap | The runtime stack holds a few thousand frames. A stack you build on the heap holds millions. |
| The same sub-problem is solved again and again — naive fib | Memoisation, or a bottom-up loop | Each value is then computed once instead of thousands of times, turning O(2ⁿ) into O(n). |
| The recursion is a straight sweep — sum a list, reverse a string | A for loop | Same time, O(1) stack instead of O(n), and no overflow to worry about. |
07 Interview questions
Say these out loud
The unwind question is the one that separates people who have read about recursion from people who have traced it.
What is recursion?
What are the two questions you ask before writing a recursive function?
What actually happens in memory when a function calls itself?
Walk me through factorial(4).
Why does no multiplication happen on the way down?
What causes a stack overflow?
What is the time and space complexity of recursive factorial?
How do you work out how deep a recursion will go?
Why is naive fib(n) exponential when factorial(n) is only linear?
What is tail recursion, and does it help?
Recursion or iteration — which do you actually reach for?
08 Practice problems
Base case first, every time
For each one, write the base case before the recursive call. Then check that the recursive case actually reaches it from every legal input.