210 likes | 278 Views
ECE 103 Engineering Programming Chapter 54 Recursion. Herbert G. Mayer, PSU CS Status 6/4/2014 Initial content copied verbatim from ECE 103 material developed by Professor Phillip Wong @ PSU ECE. Syllabus. Recursion Process Fibonacci Sequence Quicksort Sierpinski Triangle.
E N D
ECE 103 Engineering ProgrammingChapter 54Recursion Herbert G. Mayer, PSU CS Status 6/4/2014 Initial content copied verbatim from ECE 103 material developed by Professor Phillip Wong @ PSU ECE
Syllabus • Recursion Process • Fibonacci Sequence • Quicksort • Sierpinski Triangle
Recursion Process A recursive function is a function that invokes itself. Recursion is a powerful and elegant method to solve certain types of problems. Recursion decomposes a problem into smaller subproblems of exactly the same form as the original problem. 2
Towers of Hanoi Koch Snowflake 3
Function call mechanics: When a function is called, these items are saved (pushed) onto a call stack: Return address Function parameters Local data When the function is done: The stored items are removed (popped) from the call stack. Control returns back to the code following the original call. 4
Recursive function call: Pending function data are placed on the call stack each time the function invokes itself. A base case determines when recursion stops. It is a conditional test that halts recursion when: The problem cannot be decomposed any further. A predefined recursion depth is reached. Once the base case is reached, the recursion begins backtracking to return pending values. 5
#include <stdio.h> /* This function adds up the numbers from 1 to n using ITERATION */ int sum (int n) { int psum = 0; /* Partial sum accumulator */ int k; for (k = 1; k <= n; k++) /* Iteration */ psum = psum + k; return psum; } int main (void) { printf("\nFinal sum(5) = %d\n", sum(5)); return 0; } ACTUAL OUTPUT: sum(5) = 15 6
#include <stdio.h> /* This function adds up the numbers from 1 to n using RECURSION */ int sum (int n) { printf("sum(%d) = ", n); if (n <= 1) /* Base case */ { printf("1\n"); return 1; } else /* Recursion */ { printf("%d + sum(%d)\n", n, n-1); return n + sum(n - 1); } } int main (void) { printf("\nFinal sum(5) = %d\n", sum(5)); return 0; } ACTUAL OUTPUT: sum(5) = 5 + sum(4)sum(4) = 4 + sum(3)sum(3) = 3 + sum(2)sum(2) = 2 + sum(1)sum(1) = 1→sum(5) = 15 7
Potential Problems: Deep recursion may require excessive memory storage. Recursion can be inefficient due to excessive recomputation. If the base case is never satisfied, the recursion is infinite (until all memory becomes exhausted). Recursion may not converge if the subproblems do not become smaller. 8
Fibonacci Sequence Fn = { 0 for n=0, 1 for n=1, and Fn-1 + Fn-2 for n>=2 } →0, 1, 1, 2, 3, 5, 8, 13, 21, … /* This is the iterative (non-recursive) version */ long int fib (int n) { long int previous = -1; long int result = 1; long int sum; int i; for (i = 0; i <= n; ++i) { sum = result + previous; previous = result; result = sum; printf("i=%d sum=%ld previous=%ld result=%ld\n", i, sum, previous, result); } return result; } ACTUAL OUTPUT FOR fib(5): i=0 sum=0 previous=1 result=0 i=1 sum=1 previous=0 result=1 i=2 sum=1 previous=1 result=1 i=3 sum=2 previous=1 result=2 i=4 sum=3 previous=2 result=3 i=5 sum=5 previous=3 result=5 9
Order of calls for fib(5): fib(5)= fib(4) + fib(3) fib(4)= fib(3) + fib(2) fib(3)= fib(2) + fib(1) fib(2)= fib(1) + fib(0) fib(1)= 1 fib(0) = 0 fib(1)= 1 fib(2)= fib(1) + fib(0) fib(1)= 1 fib(0) = 0 fib(3)= fib(2) + fib(1) fib(2)= fib(1) + fib(0) fib(1)= 1 fib(0) = 0 /* This is the recursive version */ long int fib (int n) { if ( n == 0 || n == 1 ) /* base case */ return n; else /* recursion */ return fib(n-1) + fib(n-2); } Tail-recursive functions can always be rewritten as iterative functions. (Tail-recursive means the recursion occurs in the last statement.) 10
Quicksort Quicksort is a sorting algorithm developed by Tony Hoare in 1960. On average, it makes O(n log n) comparisons to sort n items. Quicksort partitions data into two smaller sub-lists and then recursively sorts each sub-list. 11
From: Wikipedia article Quicksort (in-place version) Partition Function // left is the index of the leftmost element of the subarray // right is the index of the rightmost element of the subarray (inclusive) // number of elements in subarray = right-left+1 function partition (array, left, right, pivotIndex) pivotValue := array[pivotIndex] swap array[pivotIndex] and array[right] // Move pivot to end storeIndex := left for i from left to right – 1 // left ≤ i < right if array[i] <= pivotValue swap array[i] and array[storeIndex] storeIndex := storeIndex + 1 swap array[storeIndex] and array[right] // Move pivot to its final place return storeIndex 12
Sorting Function function quicksort(array, left, right) // If the list has 2 or more items if left < right choose any pivotIndex such that left ≤ pivotIndex ≤ right // Get lists of bigger and smaller items and final position of pivot pivotNewIndex := partition(array, left, right, pivotIndex) // Recursively sort elements smaller than the pivot quicksort(array, left, pivotNewIndex - 1) // Recursively sort elements at least as big as the pivot quicksort(array, pivotNewIndex + 1, right) 13
Sierpinski Triangle From: http://www.cse.nd.edu/~dthain/courses/cse20211/fall2011/lab5 • Each triangle is recursively divided into four sub-triangles: • one at each corner • one in the center 14
Graphics Support: Using a graphics library, we write a function to draw a single triangle: void draw_triangle (float x1, float y1, float x2, float y2, float x3, float y3) { /* Replace these with commands of actual graphics library */ draw_line( x1,y1, x2,y2 ); draw_line( x2,y2, x3,y3 ); draw_line( x3,y3, x1,y1 ); } (x1,y1) (x3,y3) (x2,y2) 15
Step 1 of recursion function: Define the drawing step. void fractal_triangle (float x1, float y1, float x2, float y2, float x3, float y3) { /* Base case will go here */ /* Drawing step */ draw_triangle( x1,y1, x2,y2, x3,y3 ); /* Recursive step will go here */ } (x1,y1) (x3,y3) (x2,y2) 16
Step 2 of recursion function: Define the recursion step. void fractal_triangle (float x1, float y1, float x2, float y2, float x3, float y3) { /* Base case will go here */ /* Drawing step */ draw_triangle( x1,y1, x2,y2, x3,y3 ); /* Recursive step */ fractal_triangle( x1,y1, (x1+x2)/2,(y1+y2)/2, (x1+x3)/2,(y1+y3)/2 ); fractal_triangle( (x1+x2)/2,(y1+y2)/2, x2,y2, (x2+x3)/2,(y2+y3)/2 ); fractal_triangle( (x1+x3)/2,(y1+y3)/2, (x2+x3)/2,(y2+y3)/2, x3,y3 ); } (x1,y1) (x3,y3) (x2,y2) 17
Step 3 of recursion function: Define the base case. void fractal_triangle (float x1, float y1, float x2, float y2, float x3, float y3) { /* Base case step */ if ( fabs(x2 – x1) < LIMIT ) /* Stop when side length gets too short */ return; /* Drawing step */ draw_triangle( x1,y1, x2,y2, x3,y3 ); /* Recursive step */ fractal_triangle( x1,y1, (x1+x2)/2,(y1+y2)/2, (x1+x3)/2,(y1+y3)/2 ); fractal_triangle( (x1+x2)/2,(y1+y2)/2, x2,y2, (x2+x3)/2,(y2+y3)/2 ); fractal_triangle( (x1+x3)/2,(y1+y3)/2, (x2+x3)/2,(y2+y3)/2, x3,y3 ); } (x1,y1) (x3,y3) (x2,y2) 18
1 5 9 13 2 10 6 3 4 12 8 11 7 19
Julius Tree 20