COMPUTER ENGINEER

← BlogDATA STRUCTURES / ALGORITHMSPython example pack ↓

Memory and recursion · 07 / 53

Recursion, call trees and explicit stacks

Understand → trace → implement → justify

2 min reading · allow extra time for practice

Recursion requires a base case, a smaller subproblem and combination logic. Factorial follows n!=n·(n−1)! with 0!=1. Reject negative inputs so the process cannot move away from its base case. Active frames consume space; Python does not guarantee tail-call elimination.

Naive Fibonacci repeatedly solves identical subproblems. Its call tree may contain exponentially many calls while its maximum active stack depth is O(n). Memoisation removes repeated subproblems; iteration can also remove the call stack.

Recursive tree DFS is readable but a long chain may exceed stack limits. An explicit stack records pending nodes and, if necessary, continuation state. Preorder, inorder and postorder differ in when a node is processed. Prove recursive correctness through induction on the subproblem contract.

A worked trace

fact(4) descends to fact(0), then returns 1,1,2,6,24. The deepest point has five active frames.

Cost and assumptions

Factorial uses O(n) operations under unit-cost arithmetic and O(n) recursive stack space; big-integer multiplication adds cost.

Executable example

Run with Python 3. Assertions check a small example; they do not constitute a general correctness proof. Some advanced examples are explicitly small models or reference oracles, not full production implementations.

Python 3
def factorial(n):
    if n < 0:
        raise ValueError("negative factorial")
    result = 1
    for x in range(2, n + 1):
        result *= x
    return result
assert factorial(4) == 24

TEST YOUR UNDERSTANDING

Your turn

What would you use for DFS on a million-node chain?

Reveal the reasoning

Use an explicit stack and visited set. Raising recursion limits is not a robust fix; store iterator/index state when continuations matter.

Take it further

  1. Write down the input contract and the invariant before changing the example.
  2. Add empty, boundary, duplicate and adversarial cases where they are relevant. Compare with a simple oracle.
  3. Derive the cost under the stated model; measure several input sizes and explain discrepancies.

Primary reading & lecture notes

Original explanations in this course; these references provide proofs and further reading. Source links may cover the broader module.

MIT 6.006 · Introduction to Algorithms ↗
Solve the exercise before moving on.