Counting binary trees (recursive)
Count the binary trees with n nodes straight from the recursive definition; the call tree shows why the dynamic-programming version (Catalan numbers) is better.
Describe a binary tree with n nodes by its root and its subtrees. If the left subtree has i nodes, the right one
has n − 1 − i, and every pair of subtrees makes a new tree:
- Time:
O(3ⁿ) - Space:
O(n) - Horowitz–Sahni, chapter 5
- Grimaldi, chapter 10
3 nodes: 5 trees (2 + 1 + 2, depending on how many nodes are on the root's left).
def count_trees(n):# The number of binary trees with n nodes: the root, then i nodes on the left and n − 1 − i on the right.if n <= 1:return 1total = 0for left in range(n):right = n - 1 - lefttotal = total + count_trees(left) * count_trees(right)return total
Start
Recursion tree
Filled orange = running call · Orange outline = still on the stack · Grey = finished
Local variables
Orange = changed in this step
Call stack
- count_trees()line 1
Explanation
The idea
Describe a binary tree with n nodes by its root and its subtrees. If the left subtree has i nodes, the right one
has n − 1 − i, and every pair of subtrees makes a new tree:
T(n) = Σ T(i) · T(n − 1 − i) for i = 0 … n − 1, T(0) = T(1) = 1
The answers are the Catalan numbers: 1, 1, 2, 5, 14, 42, …
Why it is slow
Each call calls several smaller subproblems, and the same subproblems are computed again and again; the number of
calls is exponential. The dynamic-programming version (the "Catalan numbers" page) computes each T(k) once:
O(n²).
What to watch in the trace
- Look at the call tree: nodes with the same
nrepeat many times.