Russian dolls
Recursion
The analogy
To count nested dolls you open one and ask the same question of what is inside: "how many dolls in there?" Eventually you open a doll that is solid โ that is the base case, and the answers add back up on the way out. A problem that contains a smaller copy of itself is a recursive problem.
Visualizer
Dolls inside dolls
step 1 / 11bottom
count(doll) on a set of nested dolls. Each call will ask the same question of a smaller doll.stack depth 0
๐ In depth โ the full reference
Recursion โ everything worth knowing
- Anatomy: BASE CASE (the smallest doll โ answered directly, no recursion) + RECURSIVE CASE (shrink the problem, trust the smaller call). Missing or unreachable base case = infinite descent = stack overflow.
- The leap of faith: assume factorial(nโ1) already works and only check that your step (ร n) is right. Verifying the whole chain in your head is how people get lost.
- Every call pushes a frame (m0l7's vending machines) โ so recursion costs O(depth) memory even when the maths is O(1).
- Recursion โ iteration: anything recursive can be rewritten with an explicit stack, and simple tail-shaped recursions collapse to plain loops. Use recursion when the PROBLEM is recursive: trees, divide and conquer, backtracking.
- The naive-fibonacci trap: fib(n) calling fib(nโ1) AND fib(nโ2) re-solves the same subproblems exponentially โ O(1.6โฟ). Caching answers (memoization) collapses it to O(n) โ that observation IS dynamic programming, Module 8.
- Where you have already used it: merge sort and quicksort (halves), DFS (neighbours) โ recursion was load-bearing three lessons before it got named.
Python specifics
import sys
print(sys.getrecursionlimit()) # 1000 โ Python's guard rail
# Exceed it -> RecursionError (a clean exception, not a crash).
# CPython does NOT optimise tail calls โ Guido chose readable tracebacks.
from functools import lru_cache
@lru_cache(maxsize=None) # memoization in one line
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(500)) # instant โ and arbitrary precisiondef count(doll):
if doll.inner is None:
return 1 # base case
return 1 + count(doll.inner)
import sys
sys.getrecursionlimit() # 1000 by default
# every pending call costs a stack frameCheck yourself
What stops a recursion?
Practice โ write it yourself
factorial(n) โ recursively: the machine that presses its own button. Base case first (0! = 1), or the stack grows forever.
Python 3 ยท runs in your browser ยท your draft is saved locally
๐ My notessaved in this browser