220 likes | 594 Vues
Recursion. Outline. What is recursion? Rules of recursion Mathematical induction The Fibonacci sequence Summary. What is recursion?. A recursive method is a method that directly or indirectly calls itself. Example: definition of factorials. 5! = 5 × 4 × 3 × 2 × 1
E N D
Outline • What is recursion? • Rules of recursion • Mathematical induction • The Fibonacci sequence • Summary
What is recursion? • A recursive method is a method that directly or indirectly calls itself. Example: definition of factorials 5! = 5 × 4 × 3 × 2 × 1 n! = n × n − 1 × n − 2 × . . . × 1 (n − 1)! = n − 1 × n − 2 × . . . × 1 factorial(n) = n × factorial(n − 1) factorial(1) = 1
Example: recursive implementation of factorial • What happens if we callint x = factorial(4)?. public int factorial(int n) factorial(4)= 24 factorial(3)= 6 factorial(2) = 2 factorial(4)= 1 { if (n == 1) return 1; return n * factorial(n - 1); } return 4 * factorial (3); return 3 * factorial (2); return 2 * factorial (1); Return 1; Eventually, x is assigned the return value of factorial(4), i.e. 24
The basics of recursion • How can a method F solve a problem by calling itself? • The key: F calls itself on a simpler problem! • Problems solvable by recursion can be reduced into one or moresmaller and similar problems. • In general, recursion has 2 cases: • Induction case: solved by reducing the problem. • Base case: simple enough, requires no more reduction.
The rules of recursion 1. Base case 2. Make progress 3. You gotta believe 4. Compound interest rule Always have at least one case that can be solved without recursion. To avoid infinite recursion, any recursive call should progress towardsthe base case. Always assume that the recursive call works. Never duplicate work by solving the same instance of a problem inseparate recursive calls.
“Believing” in the induction case Example: • Consider factorial(n). • Assume factorial(n − 1) computes the correct result. • What must be done to get factorial(n) from factorial(n − 1)? • Multiply by n. This is true whether you’re computing factorial(4)or factorial(400000).You don’t have to trace this 400000 times to convince yourself!
How NOT to do recursion • What happens if we call bad(n) with any value of n > 0? • Infinite recursion! public static int bad (int n) { if (n == 0) return 0; return bad(n * 3); }
How does recursion work? • The Java Virtual Machine keeps track of method calling usingactivation records. • An activation record contains relevant info, such as: • Values of parameters • Values of local variables • Which line of code was being executed • Every time a method call is made, a new activation record iscreated. • What would make a good data structure for a collection of theserecords? A Stack!
Outline Activation record stack • When method S is called, an activation record for S is pushedonto the stack, making it the currently active method. • When the method returns, the stack is popped and the activationrecord that is the new top of the stack contains the restoredvalues.
Too much recursion! • On “my” computer, calling s(12516) can’t be handled! Why? • The computer runs outs of memory storing the activation record stack! • A simple loop would have worked... public static long s (int n) { if (n == 1) return 1; else return s (n - 1); }
Induction: the mathematical basis for recursion Mathematical induction is a method for proving theorems. Example: • How do we prove this is true? • We can easily test it for N = 1, perhaps even for 2 <= N <= 10. • However, this is not proof that the theorem holds for all N >= 1. Theorem For P any integer N >= 1, the sum of the first N integers, given by , ,equals N(N + 1)/2.
Proving the theorem with induction • Prove it.
Fibonacci numbers • The Fibonacci sequence F0, F1, . . . , Fi is a very famoussequence of numbers. • It is defined as follows: • F0 = 0 • F1 = 1 • Fi = Fi-1 + Fi-2 • Thus: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, . . .
Computing Fibonacci recursively • This works. However, it’s really slow. Computing F40 takes almosta minute on some modern PCs! • To compute fibo(n), we recursively compute fibo(n-1) andfibo(n-2). • However, we already computed fibo(n-2) in the process ofcomputing fibo(n-1). public static long fibo(int n) { if( n <= 1 ) return n; else return fibo( n - 1 ) + fibo( n - 2 ); }
Wasting time... • F40 makes over 300 million recursive calls. The growth rate isexponential! • Remember the last rule of recursion: Never duplicate work bysolving the same instance of a problem in separate recursive calls. • The solution: remember the previous Fibonacci numbers.
Remembering the previous numbers • Storing the result of previous computation: this technique is calleddynamic programming or memorization. • There is a more (space) efficient implementation. How? public static long fibo2 (int n) { if (n <= 1) return n; long result[] = new long[n + 1]; result[0] = 0; result[1] = 1; for (int ii = 2; ii <= n; ii++) result[ii] = result[ii - 1] + result[ii - 2]; return result[n]; }
Remembering just the last two numbers public static long fibo3 (int n) { if (n <= 1) return n; long fib1 = 0; long fib2 = 1; long result; for (int ii = 2; ii <= n; ii++) {result = fib2 + fib1; fib1 = fib2; fib2 = result;} return result; }
An efficient recursive implementation public static long fibo4 (int n) static long fiboHelp (long x, long y, int n) { return fiboHelp(0,1,n) } { if (n == 0) return x; else if ( n == 1 ) return y; else return fiboHelp (y, x+y, n-1); }
Summary • Recursion is a powerful problem solving tool and has many uses. • The foundation of recursive functions is mathematical induction, away of provingtheorems. • The rules of recursion: • Base case. • Progress towards the base case. • Always assume the recursive call works. • Never duplicate work by solving the same instance of a problem inseparate recursive calls. • Dynamic programming: saving the results of previouscomputation.