1 / 35

Recursion

Recursion. Basic Recursions. Basic Recursions. Break a problem into smaller identical problems Each recursive call solves an identical but smaller problem. Stop the break-down process at a special case whose solution is obvious, (termed a base case )

yadid
Download Presentation

Recursion

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. Recursion

  2. Basic Recursions Basic Recursions • Break a problem into smaller identical problems • Each recursive call solves an identical but smaller problem. • Stop the break-down process at a special case whose solution is obvious, (termed a base case) • Each recursive call tests the base case to eventually stop. • Otherwise, we fall into an infinite recursion.

  3. Basic Recursions Example 1: The Sum of the First NPositive Integers • Definition: sum(n)= n + (n-1) + (n-2) + … + 1 for any integer n > 0 • Recursive relation; sum(n)= n + [(n-1) + (n-2) + … + 1] = n +sum(n-1) Looks so nice, but how about n == 1? sum(1) = 1+sum(0), but the argument to sum( ) must be positive • Final recursive definition: sum(n) = 1 if n = 1 (Base case) = n + sum(n-1) if n > 1 (Recursive call)

  4. Basic Recursions Recursive Definition of sum(n) intsum(int n) { if (n == 1) // base case return 1; else return n +sum(n-1); // recursive call A } How should I test this function’s correctness? Use the box method: A box has each function’s local environment ex. cout << sum(3); 1. Arguments 2. Local variables 3. Place holder for the value returned by a called function 4. A return value n = 3 A: sum(n-1) = ? return ?

  5. Basic Recursions n = 2 A: sum(n-1)=? return ? n = 1 return 1 3 1 6 3 Box trace of sum(3) cout << sum(3); n = 3 A: sum(n-1)=? return ? n = 3 A: sum(n-1)= ? return ? n = 2 A: sum(n-1)=? return ? n = 1 return 1 Each box corresponds to a function’s activation record or stack.

  6. Basic Recursions Example 2: The Factorial of n • Definition: factorial(n) = n * (n-1) * (n-2) * … * 1 for any integer n > 0 factorial(0) = 1 • Recursive relation; factorial(n) = n * [(n-1) * (n-2) * … * 1] = n * factorial(n-1) Looks so nice, but how about n = 1? factorial(1) = 1 * factorial(0) but the argument to factorial( ) must be positive • Final recursive definition: factorial(n) = 1 if n = 1 = n *factorial(n-1) if n > 1

  7. Basic Recursions Recursive Definition of facotrial(n) int fact(int n) { if (n == 1) // base case return 1; else return n * fact(n-1); // recursive call A } Trace its execution using the box method: ex. cout << fact(3); n = 3 A: fact(n-1) = ? return ?

  8. Basic Recursions n = 2 A: fact(n-1)=? return ? n = 1 return 1 2 1 6 2 Box trace of fact(3) cout << fact(3); n = 3 A: fact(n-1)=? return ? n = 3 A: fact(n-1)= ? return ? n = 2 A: fact(n-1)=? return ? n = 1 return 1

  9. Basic Recursions Precondition of fact(n) • Precondition: n >= 1 • If the precondition is violated, what happen? • Fact(0) calls fact(-1), which calls fact(-2), …. • For robustness, given a negative number or 0, fact should stop a recursive call. Always correct to recursions int fact(int n) { if (n <=1) // base case for n = 1 or bad args. return 1; else return n * fact(n-1); // recursive call A }

  10. Basic Recursions Example 3: Printing Numbers in Any Base How to convert a decimal to a hexadecimal Dividend Remainder 16) 1234567890(10)……..… 16) 7716049(10)………6 16) 482253(10)………1 16) 30140(10)…13(D) 16) 1883(10)…12(C) 16) 117(10)…11(B) 16) 7(10)……....5 16) 0(10)……....7 2. Print each reminder from the bottom: 75BCD16(16) 1. Divide by a base(16)

  11. Basic Recursions Recursive Definition of printNum(n,base) voidprintNum(int n, int base) { static string DIGIT_TABLE = “0123456789abcdef”; if (n >=base) // recursive call A printNum( n / base, base ); // else n < base base case cout << DIGIT_TALBE[ n % base ]; } Trace its execution using the box method: ex. cout << print(123456789, 16); n = 123456789, base = 16 A: fact(n-1) returns nothing Print: n % base = ? return nothing

  12. Basic Recursions Example 4: Binary Search An entire sorted list First half Second half • The search divides a list into two small sub-lists till a sub-list is no more divisible. • Each step needs the top/tail indexes and a target item. First half Second half First half Can we call binarySearch( ) recursively?

  13. Basic Recursions Binary Search (Recursive Version) int binarySearch( const int array[], int top, int tail, int target ) { int mid = (top + tail)/2; if ( target == array[mid] ) return mid; else if ( target < array[mid] ) return binarySearch( array, top, mid-1, target ); else if ( target > array[mid] ) return binarySearch( array, mid+1, tail, target ); } Question: if it does not find the target, how can we stop this program?

  14. Basic Recursions Binary Search Revisited i i+1 35 47 top tail mid = (top + tail)/2 = (i + i+1)/2 = i top = mid + 1 = i + 1 In the next recursive call, top = i + 1; tail = i; thus top > tail!! Base cases: (1) if (target == array[mid]) return mid; (2) if top > tail return –1;

  15. Basic Recursions Binary Search (Correct Recursive Version) int binarySearch( const int array[], int top, int tail, int target ) { int mid = (top + tail)/2; if ( target == array[mid] ) return mid; // find it else if ( top > tail ) return -1; // cannot find it else if ( target < array[mid] ) return binarySearch( array, top, mid-1, target ); else if ( target > array[mid] ) return binarySearch( array, mid+1, tail, target ); }

  16. Basic Recursions Example 5: Multiplying Mice Month 1 Month 2 Quite difficult to keep track of the population explosion. Month 3 Month 4 Month 5 Month 6 Babies Month 7 Recursive relation: #babies in Month 7= #mice in Month 5 #adults in Month 7 = #mice in Month 6

  17. Basic Recursions The Fibonacci Sequence • mice(n) = mice(n-1) + mice(n-2) • Then, what are base cases? • Recursive definition: mice(1) = mice(0) + mice(-1) can’t happen. Thus, mice(1) = 1; mice(2) = mice(1) + mice(0) can’t happen, either. Thus, mice(2) = 1; mice(n) = 1 if n = 1 or 2 mice(n-1) + mice(n-2) if n > 2

  18. Basic Recursions m(5) Return m(4)+m(3) m(4) Return m(3)+m(2) m(4) Return m(3)+m(2) m(3) Return m(2)+m(1) m(3) Return m(2)+m(1) m(2) Return 1 m(3) Return m(2)+m(1) m(2) Return 1 m(2) Return 1 m(1) Return 1 m(2) Return 1 m(1) Return 1 m(2) Return 1 m(1) Return 1 Tracing mice(n) m(6) Return m(5)+m(4) 8 5 3 3 2 2 1 2 1 1 1 1 1 1 1

  19. Recursive Applications Recursive Applications • Discrete Mathematics (Combinatorics, Puzzles, Coding Theory) • Tower of Hanoi and Gray Code • Divide and Conquer • Mergesort, Convex Hall, and Fast Fourier Transform • Backtrack • 8 Queens, Maze and Classic Chess Program • Fractal Figures • Koch, Sierpinski Allowhead, Gosper, Hilbert, and Dragon curves

  20. Recursive Applications Towers of Hanoi A B C Find how to move dishes from A to B using C. Restrictions:

  21. Recursive Applications A B C A B C A B C A B C Solution In order to move n dishes from A to B via C, move(n, A, B, C) if we could move n-1 dishes from A to C via B, move(n-1, A, C, B) we could move a dish, (i.e., the last one) from A to B (via C), move(1, A, B, C) and thereafter, we would move n-1 Dishes from C to B via A! move(n-1, C, B, A)

  22. Example Code #include <iostream> #include <stdlib.h> using namespace std; void move( int n, char orig, char dest, char temp ) { if ( n == 1 ) cout << "move disk 1 from " << orig << " to " << dest << endl; else { move( n - 1, orig, temp, dest ); cout << "move disk " << n << " from " << orig << " to " << dest << endl; move( n - 1, temp, dest, orig ); } } int main( int argc, char* argv[] ) { int nDishes = atoi( argv[1] ); move( nDishes, 'A', 'B', 'C' ); cout << "completed" << endl; return 0; }

  23. Recursive Applications Tracing move(n, A, B, C) move(3, A, B, C) 4 move(2, A, C, B) move(1, A, B, C) move(2, C, B, A) Locally, A is A, C is B, B is C. Locally C is A, B is B, A is C. 1 5 move(1, C, A, B) move(1, A, B, C) 2 6 move(1, C, B, A) move(1, A, C, B) 7 3 move(1, A, B, C) move(1, B, C, A)

  24. Recursive Applications Divide-and-Conquer AlgorithmsComputational Geometry – Finding a Convex Hall • Divide: • Divide a problem into two sub-problems recursively so that the sub-problems are calculated by themselves. • Conquer: • Form a new solution from the solutions answered by the sub-problems The convex hull problem Trivial algorithm: O(n2) Divide & conquer: O(nlogn)

  25. Recursive Applications Q Q Q Q Q Q Q Q BacktrackTrace every combination until encountering a solution • The eight queens problem • Place 8 queens on a 8 * 8 chessboard so that no queen can attack any other queen. • Place a queen from the column 0 to 7 as checking if the queens placed on the former columns can attack the current queen.

  26. Recursive Applications BacktrackThe Eight Queen Problem • A Naïve Solution Q ?? for ( int col = 0; col < 7; col++ ) { for ( int row = 0; row < 7; row++ ) { if ( safeLocation( table, row, col ) ) { table[row][col] = true; break; } } // oops! No safe row to place a new queen // I got to go back to the previous column! } Q Q Q Q Q • Then, how can I go back to the previous column? Just col--?

  27. Recursive Applications BacktrackThe Eight Queen Problem • A Recursive Solution: [0,0] -> [0,1] NO [1,1] NO [2,1] -> [0,2] NO [1,2] NO [2,2] NO [3,2] NO [4,2] -> [0,3] NO [1,3] -> [0,4] NO [1,4] NO [2,4] NO [3,4] -> [0,5] NO [1,5] NO [2,5] NO [3,5] NO [4,5] NO [5,5] NO [6,5] NO [7,5] NO [4,4] NO [5,4] NO [6,4] NO [7,4] -> [0,5] Q ?? Q Q Q Q Q

  28. Recursive Applications BacktrackThe Eight Queen Problem bool addQueen( bool t[SIZE][SIZE], int col ) { if ( col >= SIZE ) return true; // all cols have been examined for ( int row = 0; row < SIZE; row++ ) { if ( safeLocation( t, row, col ) ) { // this row may be a candidate t[row][col] = true; // place a new queen; if ( addQueen( t, col + 1 ) ) return true; // all the following cols were filled else t[row][col] = false; // A wrong position. Try the next row } } return false; // all rows examined, but no candidates } int main( ) { bool table[SIZE][SIZE]; // there are no matrix templates in STL init( table ); // all table[i][j] = false; if ( addQueen( table, 0 ) ) print( table ); else cout << "no solution" << endl; }

  29. Recursive Applications Fractal CurvesDrawing a Ruler // java code to draw a ruler void drawRuler( Graphics g, int left, int right, int level ) { if ( level < 1 ) return; int mid = ( left + right ) / 2; g.drawLine( mid, 80, mid, 80 – level * 5 ); drawRuler( g, left, mid – 1, level – 1 ); drawRuler( g, mid + 1, right, level – 1 ); } mid at level 1 mid at level 1 mid at level 1 mid at level 1 Initial right Initial left mid at level 2 mid at level 2 mid at level 3

  30. Recursive Applications Fractal CurvesDrawing a Koch Curve using a Turtle class Turtle { public: Turtle( float initX=0.0, float initY=0.0, float initAngle=0.0 ) { ~Turtle( ); void draw( float d ); // draw a line from the current position for distance d void move( float d ); // simply move from the current position for distance d void turn( float a ); // turn left by angle a private: float angle; // presented in degree but not in radian oftream out; }; int main( ) { Turtle t; t.draw( 10 ); t.turn( 45 ); t.move( 10 ); t.draw( 10 ); }

  31. Recursive Applications Fractal CurvesDrawing a Koch Curve using a Turtle class Koch : Turtle { public: Koch( float initX=0.0, float initY=0.0, float initAngle=0.0) : Turtle( initX, initY, initAngle ) { ) ~Koch( ); curve( int level, float length ) { if ( level > 1 ) { curve( level – 1, length ); turn( 60 ); curve( level – 1, length ); turn( -120 ); curve( level – 1, length ); turn( 60 ); curve( level – 1, length ); } draw( length ); } }; int main( ) { Koch k(100, 100, 0); k.curve( 3, 10 ); } Draw the level-3 Koch curve here

  32. Efficiency Recursion and Efficiency • Programmability • Capable of breaking down a complex problem • Based on mathematical induction • Efficiency • The overhead associated with function calls (Bookkeeping the current stack and creating a new one) • The inherent inefficiency of some algorithm (Repeating the same computation)

  33. Efficiency m(5) Return m(4)+m(3) m(4) Return m(3)+m(2) m(4) Return m(3)+m(2) m(3) Return m(2)+m(1) m(3) Return m(2)+m(1) m(2) Return 1 m(3) Return m(2)+m(1) m(2) Return 1 m(2) Return 1 m(1) Return 1 m(2) Return 1 m(1) Return 1 m(2) Return 1 m(1) Return 1 Efficiency of mice(n) O(2n) m(6) Return m(5)+m(4)

  34. Efficiency Iterative Solution of mice(n) int iterativeMice(int n) { int previous = 1; int current = 1; int next = 1; for (int i = 3; i <= n; ++i) { next = current + previous; previous = current; current = next; } return next; } Efficiency of mice(n): O(n-2)=O(n)

  35. Efficiency Recursion versus Iteration Problems Recursion Iteration Fibonacci sequence O(2n) O(n) Sum/Fact/printNum O(n) O(n) function call overhead Binary search O(log n) O(log n) Tower of Hanoi O(2n) Fractal figures (Koch) O(4n) Can you program it? N queens O(Nn) • Discover a recursive solution if it is easier. • Convert it to iteration if an iterative solution is more efficient. • When a recursion incurs more iterations • When each iteration includes a few computation

More Related