The two required parts
def factorial(n):
if n <= 1: # base case
return 1
return n * factorial(n-1) # smaller problem
If the recursive case does not make progress, the function may run until the language’s recursion limit or stack capacity is reached.
What the call stack remembers
When factorial(5) calls factorial(4), the first call pauses with its value of n and waits for the result. Each call has its own frame. Once the base case returns, frames resume in reverse order: 1 × 2 × 3 × 4 × 5 = 120. The visualizer shows those frames building on the way down and unwinding on the way back.
Choose countdown — no base case to see frames accumulate without returning. Then compare fibonacci — naive with memoised at the same input. The naive version recomputes overlapping subproblems and takes exponential time; memoization stores each result so it is computed once. This is a useful bridge to dynamic programming.
When recursion fits
Recursion often matches tree traversal, nested data, divide-and-conquer, and backtracking because each naturally contains smaller instances of the same problem. A loop is usually simpler for a flat sequence. Deep recursion can also use more stack space than an iterative solution; Python does not optimize tail calls into loops.
Common mistakes with Recursion and the Call Stack
- Missing or unreachable base case: calls never return.
- Not shrinking the problem: the recursive case repeats the same state.
- Forgetting to return the recursive result: the caller receives
None in Python. - Recomputing repeated subproblems: add memoization when the recurrence revisits states.
- Using recursion for very deep input: consider an explicit stack or loop.