Lecture P6: Recursion
Lecture P6: Recursion
What is recursion?
s
New mode of thinking. Powerful programming tool. Many computations are naturally self-referential. a Unix directory contains files and other directories Euclids gcd algorithm linked lists and trees GNU = GNUs Not Emacs
Start
s
Goal
Overview
How does recursion work? ! Just like any other function call. How does a function call work?
s
Implementing Functions
How does the compiler implement functions? ! With a STACK. Return from functions in last-in first-out (LIFO) order.
s
A function lives in a local environment: values of local variables which statement the computer is currently executing When f() calls g(), the system saves local environment of f sets value of parameters in g jumps to first instruction of g, and executes that function returns from g, passing return value to f restores local environment of f resumes execution in f just after the function call to g
FUNCTION CALL: push local environment onto stack. RETURN: pop from stack and restore local environment.
A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. iterative sum 1 int sum(int n) { int i, s = 0; for (i = 0; i <= n; i++) s += i; return s; } iterative sum 2 int sum(int n) { int s = n; while (n > 0) { n--; s += n; } return s; }
A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. sum(n-1)
recursive sum int sum(int n) { if (n == 0) return 0; return n + sum(n-1); } base case reduction step
Note that changing the variable n in sum does not change the value in the calling function.
5
A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. Can also express using SELF-REFERENCE.
s
Dont even need iteration, let alone recursion. 0 + 1 + 2 + . . . + n = n(n+1) / 2 better sum int sum(int n) { return (n * (n+1)) / 2; } Is n even?
mystery1(n) void mystery1(int n) { printf("%d\n", n); if (n % 2 == 0) mystery1(n/2); else mystery1(3*n + 1); } no base case
Unknown whether program terminates for all positive integers n. Stay tuned for Halting Problem in Lecture T4.
mystery2(n) void mystery2(int n) { printf("%d\n", n); if (n <= 1) return; else if (n % 2 == 0) mystery2(n/2); else mystery2(3*n + 1); }
10
Number Conversion
To print binary representation of integer N: Stop if N = 0. Write 1 if N is odd; 0 if n is even. Move pencil one position to left. Print binary representation of N / 2. (integer division) base case reduction step converges to base case 43 21 10 5 2 1 0 1 11 011 1011 01011 101011
11
12
convert( ) void convert(int N) { if (N == 0) return; convert(N / 2); printf("%d", N % 2); } Unix 1 if N is odd; 0 if N is even
convert( ) void convert(int N) { if (N == 0) return; convert(N / 2); printf("%d", N % 2); } 1 if N is odd; 0 if N is even
function calls Proof of correctness: convert(43)/ 2) + (N % 2) N = 2 * (N convert(21) convert(10) convert(5) convert(2) convert(1) convert(0) printf("1") printf("0") printf("1") printf("0") printf("1") printf("1")
Proof of correctness: N = 2 * (N / 2) + (N % 2)
% gcc convert.c % a.out 43 101011 Indentation level pairs statements belonging to same "invocation"
13
14
Fibonacci numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . It takes a really long time to compute F(40).
if n = 0 0 Fn = 1 if n = 1 F + Fn 2 otherwise n 1
F(0) is computed 165,580,141 times. bad Fibonacci function int F(int n) { if (n == 0 || n == 1) return n; else return F(n-1) + F(n-2); }
15
bad Fibonacci function int F(int n) { if (n == 0 || n == 1) return n; else return F(n-1) + F(n-2); }
16
DYNAMIC PROGRAMMING solution: save away intermediate results in a table. Fibonacci using dynamic programming int knownF[1000] = {0}; int F(int n) { if (knownF[n] != 0) return knownF[n]; else if (n == 0 || n == 1) return n; knownF[n] = F(n-1) + F(n-2); return knownF[n]; } Stores ith Fibonacci number in ith element.
Fact 2. Any iterative function can be written with recursion. Should I use iteration or recursion?
s
17
18
Towers of Hanoi
Move all the discs from the leftmost peg to the rightmost one.
s
Only one disc may be moved at a time. A disc can be placed either on empty peg or on top of a larger disc.
Goal
hanoi.c char getOtherPeg(char x, char y) { if (x == A && y == B) || (x == B && y == A) return C; if (x == A && y == C) || (x == C && y == A) return B; return A; }
22
Towers of Hanoi
Is world going to end (according to legend)?
s
Summary
How does recursion work?
s
Monks have to solve problem with N = 40 discs. Computer algorithm should help. ! Not really! Takes 2N - 1 steps. (assuming rate of 1 disc per second, will take 348 centuries)
Use pictures.
Alternate between two moves: ! Move smallest disc 1 peg to right (left) if N is even (odd). ! Make only legal move not involving smallest disc. See Sedgewick 5.2.
23
24
Root Finding
f(x) = x2 - x - 1
1+ 5 = 1.61803... is a root. 2
Assume f is continuous and l, r satisfy f(l) < 0.0 and f(r) > 0.0.
2 1.5 1 0.5 0 -0.5 -1 -1.5
26
0.2
0.4
0.6
0.8
1.2
1.4
1.6
1.8
2.2
Root Finding
Reduction step:
s
Root Finding
Given a function, find a root, i.e., a value x such that f(x) = 0.
Maintain interval [l, r] such that f(l) < 0, f(r) > 0. Compute midpoint m = (l + r) / 2. If f(m) < 0 then run algorithm recursively on interval is [m, r]. If f(m) > 0 then run algorithm recursively on interval is [l, m]. recursive bisection function #define EPSILON 0.000001 double f (double x) { return x*x - x - 1; } double bisect (double left, double right) { double mid = (left + right) / 2; if (right - left < EPSILON || 0.0 == f(mid)) return mid; if (f(mid) < 0.0) return bisect(mid, right); return bisect(left, mid); }
Base case (when to stop): Ideally when (0.0 == f(m)), but this may never happen!
s
root may be irrational machine precision issues Stop when (r - l) is sufficiently small. guarantees m is sufficiently close to root
27
28