04Module · Goodrich Ch. 4
Week 4 — Recursion
Linear, binary, and multiple recursion; analyzing recursive algorithms; designing recursive solutions and eliminating tail recursion.
Recursion
Factorial, ruler, binary search, file-system examples, recursion depth, and tail-call elimination.
Theory
A recursive method calls itself on a strictly smaller instance and terminates at a base case.
Recurrences like T(n) = a·T(n/b) + f(n) are solved by the Master Theorem, giving Θ bounds for divide-and-conquer.
Linear recursion makes one call (factorial); binary makes two (binary search trees, mergesort); multiple makes several (file-system walks).
Python caps recursion depth (default 1000) — convert deep tail-recursive code into a loop manually.
Key points
- Every recursion needs a base case AND demonstrable progress toward it.
- Binary search runs in O(log n); the recurrence is T(n) = T(n/2) + O(1).
- Use memoization (functools.lru_cache) to collapse repeated subproblems from exponential to polynomial.
Code examples
Binary search (recursive)
Binary search (recursive)
def binary_search(data, target, lo, hi):
if lo > hi:
return False
mid = (lo + hi) // 2
if data[mid] == target:
return True
if target < data[mid]:
return binary_search(data, target, lo, mid - 1)
return binary_search(data, target, mid + 1, hi)Memoized Fibonacci
Memoized Fibonacci
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(50)) # instant — O(n) with cache