1 / 112

Introduction to Computer Science

Introduction to Computer Science. Unit 15. Recursion The Runtime Stack. Recursion. A method that calls itself is said to be recursive (Another formulation: A message that causes itself to be sent as another message)

leal
Download Presentation

Introduction to Computer Science

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduction to Computer Science Unit 15 • Recursion • The Runtime Stack

  2. Recursion • A method that calls itself is said to be recursive • (Another formulation: A message that causes itself to be sent as another message) • We have been looking a lot at loops: for, while, and do-while loops; recursion can be used as a substitute for loops, but it can do much more • The ability to use recursion gives Java a lot of power, and gives us a new way of thinking about problem solutions

  3. Loop Example:Count Digits in "number" numberOfDigits = 0;rest = number;do {// The number of digits in number is // numberOfDigits plus the remaining // digits in rest rest = rest / 10; numberOfDigits++;} while (rest != 0);

  4. Recursion Example:Count Digits in "number" Definition of digits(n): 1 if -9 £n£ 9,digits(n) = 1 + digits(n/10) otherwise. {

  5. Recursion Example:Count Digits in "number" { 1 if -9 £n£ 9,digits(n) = 1 + digits(n/10) otherwise. digits(321) = 1 + digits(321/10) = 1 + digits(32) = 1 + (1 +digits(32/10)) = 1 + (1 +digits(3)) = 1 + (1 +(1)) = 3

  6. Recursive Definition • A definition that is self-referential • A definition that is defined in terms of simpler instances of itself • It is not a "circular definition"; that would lead nowhere • It is a "spiraling definition" that eventually terminates, and that must include a "base case", a final part of the definition that does not call itself

  7. Recursion Example:Count Digits in "number" int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )return 1;elsereturn (1 + numberOfDigits(n/10));}

  8. How to Write a Recursive Function, f(x) • If you want to compute f(x), but can't do it directly • Assume you can compute f(y), for all values y smaller than x • Define f(x) in terms of f(y) • Define the base case(s) — define f(x) directly (i.e., not in terms of f(y)) for some base value(s) of x

  9. Counting Digits Recursively, Again f(x) intnumberOfDigits(int n) {if ( (-10 < n) && (n < 10) ) return 1;elsereturn (1 + numberOfDigits(n/10));}

  10. Counting Digits Recursively, Again f(x) int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) ) return 1;elsereturn (1 + numberOfDigits(n/10));} 1. We assume we can compute f(y) for y smaller than x

  11. Counting Digits Recursively, Again f(x) int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) ) return 1;elsereturn(1 +numberOfDigits(n/10));} 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  12. Counting Digits Recursively, Again 3. Define the base case for some x not in terms of f(y) f(x) int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) ) return 1;elsereturn (1 + numberOfDigits(n/10));} 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  13. Another Example: factorial int factorial(int n) {// Recursively multiply positive numbers// 1 through nif ( (n == 0) || (n == 1) )return 1;elsereturn ( n * factorial(n - 1) );}

  14. Another Example: factorial f(x) intfactorial(int n) {// Recursively multiply positive numbers// 1 through nif ( (n == 0) || (n == 1) )return 1;elsereturn ( n * factorial(n - 1) );}

  15. Another Example: factorial f(x) int factorial(int n) {// Recursively multiply positive numbers// 1 through nif ( (n == 0) || (n == 1) )return 1;elsereturn ( n * factorial(n - 1) );} 1. We assume we can compute f(y) for y smaller than x

  16. Another Example: factorial f(x) int factorial(int n) {// Recursively multiply positive numbers// 1 through nif ( (n == 0) || (n == 1) )return 1;elsereturn(n * factorial(n - 1));} 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  17. Another Example: factorial 3. Define the base case for some x not in terms of f(y) f(x) int factorial(int n) {// Recursively multiply positive numbers// 1 through nif ( (n == 0) || (n == 1) ) return 1;elsereturn ( n * factorial(n - 1) );} 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  18. So What's Wrong with This?Recursive Definition of power( ) Compute kn int power(int k, // number to be raisedint n) { // power to which to raise return ( k * power(k, n-1) );} Right — missing the base case definition;this will go around in circles

  19. Recursive Definition of power( ) int power(int k, // number to be raisedint n) { // power to which to raise if (n == 0)return 1;elsereturn ( k * power(k, n-1) );}

  20. Recursive Definition of power( ) f(x) intpower(int k, // number to be raisedint n) { // power to which to raise if (n == 0)return 1;elsereturn ( k * power(k, n-1) );}

  21. Recursive Definition of power( ) f(x) int power(int k, // number to be raisedint n) { // power to which to raise if (n == 0)return 1;elsereturn ( k * power(k, n-1) );} 1. We assume we can compute f(y) for y smaller than x

  22. Recursive Definition of power( ) f(x) int power(int k, // number to be raisedint n) { // power to which to raise if (n == 0)return 1;elsereturn( k * power(k, n-1) );} 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  23. Recursive Definition of power( ) f(x) int power(int k, // number to be raisedint n) { // power to which to raise if (n == 0) return 1;elsereturn ( k * power(k, n-1) );} 3. Define the base case for some x not in terms of f(y) 1. We assume we can compute f(y) for y smaller than x 2. f(x) defined in terms of f(y), where y is smaller than x

  24. What's the Point? • We could write power( ) iteratively: int power(int k, int n) {int result = 1;while (n > 0) { result = result * k; n--; }return result; }

  25. Recursion Can Do Better • Recursion does add overhead to a calculation • Sometimes it is no better (or even worse) than iteration • But recursion can also be better: • Recursion can give us a solution where iteration would be much harder to define • It can open up superior, more efficient solutions, for us

  26. New Definition of power( ) Consider a better, more efficient definition of power( ): • If n is even, then kn is equal to (k(n/2))2 • If n is odd, then kn is equal tok*(k((n-1)/2))2 This leads to a divide and conquer algorithm; the method makes use of a problem half the size of the original

  27. New Definition of power( ) int power(int k, // number to be raisedint n) { // power to which to raiseif (n == 0)return 1;else {int t = power(k, n/2);if ( (n % 2) == 0 )return (t * t);elsereturn ( k * t * t ); }}

  28. A Few Points on power( ) • t = power(k, n/2) works because integer division gives us n/2 if n is even, and (n-1)/2 if n is odd (just what we wanted) • The first version of power( ) uses n multiplications to calculate the answer • This version of power( ) uses log2 n multiplications, a much smaller number • Again, recursion is not always more efficient • But recursion made the second version natural

  29. Sometimes, the Recursive Call Appears More than Once • A recursive method can call itself multiple times • It works the same way: • Assume the recursive calls work • Define the function in terms of the recursive calls • Define the base case

  30. Another example: Fibonacci if n is 1 or 2, the nth Fibonacci number is 1 if n is 3 or more, the nth Fibonacci number is the sum of the previous two Fibonacci numbers Fibonacci sequence:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…

  31. The Recursive fibonacci( ) Definition • int fibonacci (int n) { • // Recursively calculates Fibonacci number • if ( (n == 1) || (n == 2) ) • return 1; • else • return( fibonacci(n – 1) + • fibonacci(n – 2) ); • } 2. f(x) defined in terms of f(y), where y is smaller than x

  32. Another Example: recursive definition of choose( ) function • Compute binomial coefficients, "n choose k", i.e., ( ) • Given a set S of n distinct objects, for n≥1, and a number 0 ≤k≤n, how many subsets of S have exactly k elements? • Example: Set S = {1, 2, 3}, k = 2; how many subsets of S have exactly 2 elements? "3 choose 2" is 3 (that is, {1, 2}, {1, 3}, {2, 3} ). n k

  33. Recursion to the Rescue • The solution would be much more difficult without recursion • Assume we can calculate the function choose( ) for any values smaller than n and k • Now define choose( ) in terms of choose( ) over smaller n's and k's…

  34. Pick out one element of S; call it a • Every subset of S either includes a or it doesn't • We can count the subsets by counting those with a, and counting those without a, and adding them up • A k-element subset containing a is formed by choosing k - 1 elements from the remaining n - 1 elements of S, so there are ( ) such subsets • A k-element subset that excludes a is formed by choosing k elements from the remaining n - 1 elements of S, so there are ( ) such subsets n - 1 k - 1 n - 1 k

  35. Specific Example • S = {1, 2, 3}, n = 3; k = 2; how many subsets of S have exactly 2 elements? "3 choose 2" is three (that is, {1, 2}, {1, 3}, {2, 3} ) • All these sets either include "1" or they don't • Notice: • Two of the sets include "1": {1, 2} and {1, 3} • One of the sets doesn't include "1": {2, 3}

  36. Specific Example, continued • We can figure out how many sets include "1" by pretending S is {2, 3}, and looking at "n-1 choose k-1" (that is, "2 choose 1"): • There are two such sets: {2} and {3} • These correspond to the "n choose k" (that is, "3 choose 2") sets that include "1", namely {1, 2} and {1, 3}

  37. Specific Example, continued • We can figure out how many sets do not include "1" by pretending S is {2, 3}, and looking at "n - 1 choose k" (that is,"2 choose 2"): • There is one such set: {2, 3} • This corresponds to the "n choose k" (that is, "3 choose 2") set that doesn't include "1", namely {2, 3}

  38. Specific Example, finished • Add up the number of sets that do include "1" (there are two) with the number of sets that do not include "1" (there is one), and you get the final answer: three • "3 choose 2" defined in terms of • "2 choose 1" and • "2 choose 2" • "n choose k" defined in terms of • "n - 1 choose k - 1" and • "n - 1 choose k"

  39. So Far, So Good • But we are not done • What about the base case(s)? int choose(int n, int k) {return ( choose(n-1, k-1) + choose(n-1, k) );}

  40. The Base Cases • It turns out that only two base cases are required, when k is 1, and when k is n • When k is 1, then ( ) is n, because there are n 1-element subsets of an n-element set • When k is n, then ( ) is 1, because there is 1 n-element subset of an n-element set n k n k

  41. Recursive Definition of choose( ) int choose(int n, int k) {if (k == 1)return n;else if (k == n)return 1;else return ( choose(n-1, k-1) + choose(n-1, k) );}

  42. What's Happening in the Computer? • The runtime stack, which plays an important role when one method sends a message to an object, is important for understanding what's happening with recursion, too • A brief review…

  43. A Stack Handles Nesting • Let’s improve the way we think about this nesting • When method e calls method f( ), which calls method g( ), we can think of a “stack of methods” • Like putting a piece of paper on top of another piece on top of another piece... the topmost piece is the method being executed now, the others we’ll return to • Each piece of paper holds the parameters and local variables

  44. Starting Execution in main( ) public static void main (String[ ] args){.........obj.e();...} Method main( ) top STACK

  45. Call to method e( ) public static void main (String[ ] args){.........obj.e();...} void e ( ) {......obj.f( );...} Method e( )Where we came from: main, line 4 top Method main( ) STACK

  46. Executing method e( ) public static void main (String[ ] args){.........obj.e();...} void e ( ) {......obj.f( );...} Method e( )Where we came from: main, line 4 top Method main( ) STACK

  47. Call to method f( ) void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);} Method f( )Where we came from: e, line 3 top Method e( )Where we came from: main, line 4 Method main( ) STACK

  48. Executing method f( ) void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);} Method f( )Where we came from: e, line 3 top Method e( )Where we came from: main, line 4 Method main( ) STACK

  49. Call to method g( ) void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);} main (String[ ] args){.........obj.e();...} void e ( ) {......obj.f( );...} void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);} Method g( )Where we came from: f, line 4 top Method f( )Where we came from: e, line 3 Method e( )Where we came from: main, line 4 Method main( ) STACK

  50. Method g( ) finishes,the stack has its top removed void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);} main (String[ ] args){.........obj.e();...} void e ( ) {......obj.f( );...} void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);} Method f( )Where we came from: e, line 3 top Method e( )Where we came from: main, line 4 Method main( ) STACK

More Related