Recurrence & Recursion
I. In-Class Exercises
Programming Exercises
- Ackermann Function: L3081
II. Knowledge Summary
Iterative Recurrence
Recurrence here refers to solving a problem through repeated state updates in a loop. Each new state is derived directly from previous states through a recurrence formula.
Its core is to find the transition formula and compute forward step by step.
Recursion
Recursion means that a function calls itself to solve smaller subproblems of the same type, until reaching a base case.
It is especially natural for divide-and-conquer style problems.
Implementation Comparison
Recurrence / iteration:
- uses loops such as
fororwhile - updates states explicitly
- often matches the forward calculation process clearly
Recursion:
- the function calls itself
- requires a correct base case
- often expresses problem structure more elegantly
Performance and Resource Usage
Recurrence:
- better space efficiency
- usually faster because there is no function-call overhead
Recursion:
- consumes call stack space
- may cause stack overflow for deep recursion
- can be slower if there is heavy repeated computation
Typical Applications
Recurrence is suitable for:
- Fibonacci-style sequences
- simple summation problems
- many dynamic programming problems
Recursion is suitable for:
- quick sort
- merge sort
- search problems
- tree traversal
Comparison Table
| Aspect | Recurrence | Recursion |
|---|---|---|
| Mechanism | loops | self-calling function |
| Suitable problems | clear transition formula | naturally decomposable problems |
| Order | usually forward | usually from large to small |
| Common topics | sequences, greedy, DP | divide and conquer, search, tree problems |
| Main challenge | finding the formula | designing subproblems |
Execution Example
Fibonacci with Recurrence
For F(6) with F(n)=F(n-1)+F(n-2), F(1)=1, F(2)=1:
| Step | Calculation | Result |
|---|---|---|
| Initial | F(1)=1, F(2)=1 | - |
n=3 | F(3)=1+1 | 2 |
n=4 | F(4)=2+1 | 3 |
n=5 | F(5)=3+2 | 5 |
n=6 | F(6)=5+3 | 8 |
Fibonacci with Recursion
1F(6)
2|- F(5)
3| |- F(4)
4| | |- F(3)
5| | | |- F(2)
6| | | `- F(1)
7| | `- F(2)
8| `- F(3)
9| |- F(2)
10| `- F(1)
11`- F(4)
12 |- F(3)
13 | |- F(2)
14 | `- F(1)
15 `- F(2)Here F(4), F(3), and F(2) are recomputed many times.
Performance Comparison
| n | Iterative operations | Recursive calls |
|---|---|---|
| 10 | 9 | 109 |
| 20 | 19 | 13529 |
| 30 | 29 | about 1.67 million |
| 40 | 39 | about 200 million |
Naive recursion is much slower, but memoization can optimize it to the same order as iteration.
Problem-Solving Steps
When solving a "derive the unknown from the known" problem:
- Find the recurrence relation
- Determine the initial values or base cases
- Choose an implementation:
- use iteration when the direction is clear and efficiency matters
- use recursion when the problem naturally splits into subproblems
- Add memoization if recursion repeats work
Common Mistakes
- Missing the recursion base case
- Setting wrong initial values
- Recursing too deeply and causing stack overflow
- Computing in the wrong direction
- Mixing 0-based and 1-based indices in recurrence arrays
III. Homework
Programming Exercises
- Number of Moves in Tower of Hanoi: L3082