Presentation is loading. Please wait.

Presentation is loading. Please wait.

© Janice Regan, CMPT 102, Sept. 2006 0 CMPT 102 Introduction to Scientific Computer Programming Recursion.

Similar presentations


Presentation on theme: "© Janice Regan, CMPT 102, Sept. 2006 0 CMPT 102 Introduction to Scientific Computer Programming Recursion."— Presentation transcript:

1 © Janice Regan, CMPT 102, Sept. 2006 0 CMPT 102 Introduction to Scientific Computer Programming Recursion

2 © Janice Regan, CMPT 102, Sept. 2006 1 Introduction to Recursion  A function that "calls itself"  Said to be recursive  In function definition, call to same function  C allows recursion  As do most high-level languages  Can be useful programming technique  Has limitations

3 © Janice Regan, CMPT 102, Sept. 2006 2 Functions and Recursion  Divide and Conquer  Well known design method  Task is broken into smaller subtasks  Subtasks can be independent parts of the larger task  Subtasks can be copies of the same task  Use recursion when the subtasks are smaller versions of the same task!

4 © Janice Regan, CMPT 102, Sept. 2006 3 Recursive void Function  As and example consider the following task:  Print a triangle built of N rows of *s, Row zero will hold 1 *, Row N will have 2N+1 *s  N=5N=3 * *** ***** ******* ********* * *** *****

5 © Janice Regan, CMPT 102, Sept. 2006 4 Recursive problem  Consider task:  Print a triangle built of N rows of *s  Subtask 1: print first (N-1) rows of *s  Subtask 2: print Nth row of *s (2N+1 *s)  Subtasks are smaller versions of original task!  Each task involves printing a row (or rows) or *s  Therefore, the problem is of a type that can be usefully solved using a recursive method  Can use this observation to build an ‘elegant’ solution

6 © Janice Regan, CMPT 102, Sept. 2006 5 Print triangle: Recursive Design  Break problem into two cases  Simple/base case: if n=0  print one * to the screen  Recursive case: if n>0, two subtasks: 1- print the first n-1 rows of the triangle 2- print the nth row of the triangle (2N+1 *s)  Example: argument 4:  1 st subtask prints 3 rows of *s (as show on slide 3)  2 nd subtask displays 4

7 © Janice Regan, CMPT 102, Sept. 2006 6 printTriangle function void printTriangle(int N) { if( N <= 0) { return } if (N == 1) //Base case {printf(“*\n”);} else {//Recursive step printTriangle(N-1); for(i=0; i<N; i++) { printf(“**”); } printf(“*\n”); } }

8 © Janice Regan, CMPT 102, Sept. 2006 7 printTriangle: execution  Example calling program calls printTriangle(3); (which calls) printTriangle(2); (which calls) printTriangle(1); Which prints a row with 1 * and a newline then returns Which prints a row with 3 *s and a newline then returns Which prints a row with 5 *s and a newline then returns  Notice 1 st two calls call printTriangle recursively

9 © Janice Regan, CMPT 102, Sept. 2006 8 Recursion—Details (1)  Each time a function is called  The execution of the calling function stops to wait for the results of the called function to be returned  A new frame (area in memory) is assigned for the called function, arguments are copied in, and the called function begins executing.  At some point (points) in the execution of the called function, the called function will call itself  The execution of the called function stops to wait for the results of the recursive call to itself.

10 © Janice Regan, CMPT 102, Sept. 2006 9 Recursion—Details (2)  A new frame is assigned for the recursive call, arguments are copied, and the recursive call to the function begins executing.  The process continues with successive recursive calls (repetition of steps 3-5), until one of the recursive calls executes the stopping case inside the recursive function. The stopping case does not call the recursive function again but instead returns the answer for the stopping case to its calling function

11 © Janice Regan, CMPT 102, Sept. 2006 10 Recursion—Details (3)  The calling function takes the returned value and completes its own execution returning a value to its own calling function  Step 7 is repeated until the final answer is returned to the original calling function

12 © Janice Regan, CMPT 102, Sept. 2006 11 Recursion Big Picture  Outline of successful recursive function:  One or more cases where function accomplishes it’s task by making one or more recursive calls to solve smaller versions of the original task Called recursive cases  One or more cases where function accomplishes it’s task without recursive calls Called base cases or stopping cases

13 © Janice Regan, CMPT 102, Sept. 2006 12 Infinite Recursion  Base case MUST eventually be entered  If base case is not reached (an error in design or implementation has occurred) then the recursion will consider forever  Recursive calls will never end!  Remember the printTriangle example:  Base case: print a single * and return  Recursive calling stopped when base case executed

14 © Janice Regan, CMPT 102, Sept. 2006 13 Infinite Recursion Example  Consider alternate function definition: void printTriangleOOPS(int n) { printTriangleOOPS(N-1); for(i=0; i<N; i++) { printf(“**”); } printf(“*\n”); } }  Seems reasonable at first glance: BUT  There is not base case  Recursion never stops: printTriangle keeps calling itself for ever  The triangle is never printed (never get to the for loop)

15 © Janice Regan, CMPT 102, Sept. 2006 14 What is a Stack?  A stack is a specialized memory structure  Think of a stack as like a stack of sheets of paper. You always place a new sheet of paper on top of the stack, when you need a piece of paper from the stack, you take it from the top of the stack.  Called "last-in/first-out" memory structure

16 © Janice Regan, CMPT 102, Sept. 2006 15 Recursion and Stacks (1)  Recursion uses stacks. Consider a recursive function (example: printTriangle(M) ). Consider  The first call to printTriangle (made from the calling program) will be called printTriangle0 and has argument M  When this call to printTriangle (printTriangle0) is executed a frame is created in which printTriangle0 executes.  printTriangle0 executes in this frame until it calls printTriangle, then it stops and waits for the value to be returned from the recursive call to printTriangle (printTriangle1)  The frame for printTriangle0 is placed on the stack of frames

17 © Janice Regan, CMPT 102, Sept. 2006 16 Recursion and Stacks (2)  The second call to printTriangle, the first recursive call, (made in printTriangle0) will be printTriangle1 and has argument M-1  When this call to printTriangle (printTriangle1) is executed a frame is created in which printTriangle1 executes.  printTriangle1 executes in this frame until it calls itself, then it stops and waits for the value to be returned from the recursive call to printTriangle (printTriangle2)  The frame for printTriangle1 is placed on the stack of frames

18 © Janice Regan, CMPT 102, Sept. 2006 17 Recursion and Stacks (3)  The third call to printTriangle (made from printTriangle1) will be printTriangle2 and has argument M-2  When this call to printTriangle (printTriangle2) is executed a frame is created in which printTriangle2 executes.  printTriangle2 executes in this frame until it calls itself, then it stops and waits for the value to be returned from the recursive call to printTriangle (printTriangle3)  The frame for printTriangle2 is placed on the stack of frames

19 © Janice Regan, CMPT 102, Sept. 2006 18 Recursion and Stacks (4)  This pattern continues until the M-1st call to printTriangle (made from printTriangle(M-2)) called printTriangle(M-1) and has argument M-M+1=1  When this call to printTriangle (printTriangleM-1) is executed a frame is created in whiich printTriangleM-1 executes  printTriangleM-1 executes in this frame, since this is the stopping case for printTriangle, a single * is printed and the function terminates returning control to the function which called it.

20 © Janice Regan, CMPT 102, Sept. 2006 19 Recursion and Stacks (5)  The previous frame is taken off the top of the stack. The loop following the recursive call is executed and prints 3 *s. The frame is then destoyed returning control to the function which called it  The previous frame is taken off the top of the stack. The loop following the recursive call is executed and prints 5 *s. The frame is then destoyed returning control to the function which called it  This pattern continues until all frames in the stack have been executed and the triangle has been completely printed

21 © Janice Regan, CMPT 102, Sept. 2006 20 Stack Overflow  Size of stack limited  Memory is finite, too many frames in the stack will cause memory to be exhausted  Each recursive call adds a frame to the stack so a limited number of recursive calls can be supported by a stack of a particular size.  Infinite recursion always causes the stack to overflow (memory to be exhausted)  Too many levels of recursion (not infinite) can also cause the stack to overflow.

22 © Janice Regan, CMPT 102, Sept. 2006 21 Recursion Vs Iteration  Recursion not always an optimal solution  Not all languages permit recursion  Any algorithm implemented using recursion can also be implemented iteratively, using loops  Recursive implementations :  Runs slower, uses more storage  Elegant solution; less coding, less complications, faster and more straightforward to implement

23 © Janice Regan, CMPT 102, Sept. 2006 22 Recursive Functions with Return Values  Recursion not limited to void functions as in our example of printTriangle  Can have a recursive function with a return value of any type  Use same technique as for void functions 1. One or more cases iterative cases Should be smaller cases of the entire problem 2. One or more base cases

24 © Janice Regan, CMPT 102, Sept. 2006 23 Powers  For example, consider C library function pow():  twoCubed = pow(2.0,3.0);  Returns 2 raised to power 3 (8.0)  Takes two double arguments  Returns double value  Let’s write our own power() function  Our power() function will be implemented as a recursive function int power(int a, int b);

25 © Janice Regan, CMPT 102, Sept. 2006 24 Definition for power() int power(int x, int n) { if (n DBL_EPSILON) {return (power(x, n-1)*x);} else {return (1);} }

26 © Janice Regan, CMPT 102, Sept. 2006 25 Calling Function power()  Example calls:  power(2, 0); executes stopping case: return 1;  power(2, 1); executes iterative case: return (power(2, 0) * 2); this requires evaluating power(2, 0) evaluating power(2,0) evaluates stopping case returns 1; Now complete evaluation of iterative case return 1*2

27 © Janice Regan, CMPT 102, Sept. 2006 26 Calling Function power()  Another example: power(2,3); iterative case: power(2,2)*2 iterative case: power(2,1)*2 iterative case: power(2,0)*2 base case: 1 return 1*2 return 2*2 return 4*2  Recursion stops at base case  Values "returned back" up stack

28 © Janice Regan, CMPT 102, Sept. 2006 27 Thinking Recursively: factorial  Consider n! = 1 * 2 * … * n  Recursive definition of factorial: int fact(int n)  Define recursive case  Given the value of (n-1)!, what is the value of n! n! = n* (n-1)!  Define stopping case (or cases)  0! =1  1! =1  Factorial of a negative number is not defined so 0 is the smallest number that needs to be considered

29 © Janice Regan, CMPT 102, Sept. 2006 28 Recursive Design Process  Don’t trace entire recursive sequence!  Just check 3 properties: 1. No infinite recursion 2. Stopping cases return correct values 3. Recursive cases return correct values

30 © Janice Regan, CMPT 102, Sept. 2006 29 Recursive Design Check: fact()  Check fact() against 3 properties: 1. No infinite recursion: argument decreases by 1 each call Eventually must get to base case of 1 2. Stopping case returns correct value: fact(0) = fact(1) = 1 is base case Returns 1, which is correct for 0! or 1! 3. Recursive calls correct: For n>1, fact(n) returns fact(n-1)*n Plug in sample value to verify

31 © Janice Regan, CMPT 102, Sept. 2006 30 fact() int fact( ) { if (n < 0 ) { return -999; } /* indicates incorrect input */ if (n == 0 || n == 1) { return 1; /* stopping case */ } else { return ( fact(n-1) * n ); /* iterative case */ }

32 © Janice Regan, CMPT 102, Sept. 2006 31 Recursion: Quick sort  Recall our discussion of sorting, (in the unit on arrays)  Quicksort is a recursive algorithm  Each time the Quicksort function is called  the array to be sorted is divided into two parts, the left part for which all values are less than the pivot value the right part for which all values are larger than the pivot value  the Quicksort function is then recursively called First to sort the right part of the array Again to sort the left part of the array

33 © Janice Regan, CMPT 102, Sept. 2006 32 Quicksort function: void Quicksort( int InArray[], int loBound, int hiBound ) { /* block of code to break array into two parts */ /* the first part of the array hold all values < pivot */ /* the second part holds all values > pivot */ Quicksort(InArray, loBound, hiSwap-1); /* left part */ Quicksort(InArray, hiSwap+1, hiBound); /* right part */ }

34 © Janice Regan, CMPT 102, Sept. 2006 33  Unsorted Array passed into first call to Quicksort (call 0)  The array is partitioned into left part (all values pivot)  Within call 0 Quicksort is called for the left part then for the right part Sample Quick Sort: 1 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 23312197754895378616532 Pivot, middle element 531232723163719 48958675 Left part Right part

35 © Janice Regan, CMPT 102, Sept. 2006 34  When Quicksort is called for the left part, the execution of the present function (call 0 ) stops, the call0 function frame is placed on the stack, (call 0 sorts A[0]-A[12] )  A new function frame to execute Quicksort on the left part of the array is created. Execution of call 1 begins (call 1 sorts left part, A[0]- A[8]). Call 1 partitions Left part into two sections, left part2 (all values pivot of left part)  Within call 1 Quicksort is called for the left part2 then for the right part2 Sample Quick Sort: 2 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 537163732231219 Right part2 Left part2

36 © Janice Regan, CMPT 102, Sept. 2006 35  When Quicksort is called for the left part2, the execution of the present function (call 1 ) stops, the call 1 function frame is placed on the stack. (call 1 sorts A[0]-A[8] )  A new function frame to execute Quicksort on the left part2 of the array is created. Execution of call 2 begins (call 2 sorts left part2, A[0]-A[1]). Since there are only two elements in left part2 this is a stopping case. The elements are put in order and Quicksort returns.  The frame created for call2 is destroyed and the last frame added to the stack is reactivated (call 1) Sample Quick Sort: 3 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357163732231219 Right part2

37 © Janice Regan, CMPT 102, Sept. 2006 36  When Quicksort returns from sorting left part2, the execution of call 1 is reinitiated. The call 1 function frame is retrieved from the stack (call 1 sorts A[0]-A[8] ). Then call 1 calls Quicksort for right part2, the execution of call 1 stops, the call1 function frame is placed back on the stack  A new function frame to execute Quicksort on the right part2 of the array is created. Execution of call 3 begins (call 3 sorts right part2, A[3]-A[8]). Call 3 partitions right part2 into two sections, left part3 (all values pivot of right part2)  Within call 3 Quicksort is called for the left part3 then for the right part3 Sample Quick Sort: 4 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357 12 371632231912 Right part3 Left part3

38 © Janice Regan, CMPT 102, Sept. 2006 37  When Quicksort is called for the left part3, the execution of the present function (call 3 ) stops, the call 3 function frame is placed on the stack. (call 3 sorts A[3]-A[8] )  A new function frame to execute Quicksort on the left part3 of the array is created. Execution of call 4 begins (call 4 sorts left part3, A[3]-A[3]). Since there is only one element in left part3 this is a stopping case and Quicksort returns.  The frame created for call4 is destroyed and the last frame added to the stack is reactivated (call 3) Sample Quick Sort: 5 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357 12 3716322319 12 Right part3

39 © Janice Regan, CMPT 102, Sept. 2006 38  When Quicksort returns from sorting left part3, the execution of call 3 is reinitiated. The call 3 function frame is retrieved fro the stack (call 3 sorts A[3]-A[8] ). Then call 3 calls Quicksort for right part3, the execution of call 3 stops, the call 3 function frame is placed back on the stack  A new function frame to execute Quicksort on the right part3 of the array is created. Execution of call 5 begins (call 5 sorts right part3, A[5]-A[8]). Call 5 partitions right part3 into two sections, left part4 (all values pivot of right part2)  Within call 5 Quicksort is called for the left part4 then for the right part4 Sample Quick Sort: 6 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357 12 16 12 37193223 Right part4 Left part4

40 © Janice Regan, CMPT 102, Sept. 2006 39  When Quicksort is called for the left part4, the execution of the present function (call 5 ) stops, the call 5 function frame is placed on the stack. (call 5 sorts A[5]-A[8] )  A new function frame to execute Quicksort on the left part4 of the array is created. Execution of call 6 begins (call 6 sorts left part4, A[5]-A[6]). Since there are only two elements in left part3 this is a stopping case and Quicksort returns.  The frame created for call 6 is destroyed and the last frame added to the stack is reactivated (call 5) Sample Quick Sort: 7 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357 12 16 12 37233219 Right part4

41 © Janice Regan, CMPT 102, Sept. 2006 40  When Quicksort returns from sorting left part4, the execution of call 5 is reinitiated. The call 5 function frame is retrieved from the stack (call 5 sorts A[5]-A[8] ). Then call 5 calls Quicksort for right part4, the execution of call 5 stops, the call 5 function frame is placed back on the stack  A new function frame to execute Quicksort on the right part4 of the array is created. Execution of call 7 begins (call 7 sorts right part4, A[8]-A[8]). Since there is only one element in right part4 this is a stopping case and Quicksort returns.  The frame created for call 7 is destroyed and the last frame added to the stack is reactivated (call 5) Sample Quick Sort: 8 A[0]A[1]A{2]A[3]A[4]A[5}A[6]A[7]A[8]A[9]A[11]A[10]A[12] 48958675 Right part 357 12 16 12 37233219

42 © Janice Regan, CMPT 102, Sept. 2006 41  When Quicksort returns from sorting right part4, the execution of call 5 is reinitiated. The call 5 function frame is retrieved from the stack (call 5 sorts A[5]-A[8] ). Call 5 has now completed both its recursive calls.  The frame created for call 5 is destroyed and the last frame added to the stack is reactivated (call 3 sorts A[3]-A[8])  Call 3 has now completed both its recursive calls  The frame created for call 3 is destroyed and the last frame added to the stack is reactivated (call 1 sorts A[0]-A[8] ). Then call 1 calls Quicksort for right part, the execution of call 1 stops, the call 1 function frame is placed back on the stack  A new function frame to execute Quicksort on the right part of the array is created. Execution of call 8 begins (call 8 sorts right part, A[10]-A[12]). Call 8 partitions right part into two sections, left part5(all values pivot of right part)  Array is now in order Sample Quick Sort: 9


Download ppt "© Janice Regan, CMPT 102, Sept. 2006 0 CMPT 102 Introduction to Scientific Computer Programming Recursion."

Similar presentations


Ads by Google