21
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

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

Embed Size (px)

Citation preview

ECE 103 Engineering ProgrammingChapter 54Recursion

Herbert G. Mayer, PSU CSStatus 6/4/2014

Initial content copied verbatim fromECE 103 material developed by

Professor Phillip Wong @ PSU ECE

Syllabus Recursion Process Fibonacci Sequence Quicksort Sierpinski Triangle

3

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.

4

Towers of Hanoi

Koch Snowflake

5

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.

6

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.

7

#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

8

#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

9

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.

10

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=0i=1 sum=1 previous=0 result=1i=2 sum=1 previous=1 result=1i=3 sum=2 previous=1 result=2i=4 sum=3 previous=2 result=3i=5 sum=5 previous=3 result=5

11

/* 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);

}

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

Tail-recursive functions can always be rewritten as iterative functions.

(Tail-recursive means the recursion occurs in the last statement.)

12

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.

13

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 endstoreIndex := left

for i from left to right – 1 // left ≤ i < rightif array[i] <= pivotValue

swap array[i] and array[storeIndex]storeIndex := storeIndex + 1

swap array[storeIndex] and array[right] // Move pivot to its final placereturn storeIndex

14

Sorting Function function quicksort(array, left, right)

// If the list has 2 or more itemsif 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 pivotquicksort(array, left, pivotNewIndex - 1)

// Recursively sort elements at least as big as the pivotquicksort(array, pivotNewIndex + 1, right)

15

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

16

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)

(x2,y2)

(x3,y3)

17

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)

(x2,y2)

(x3,y3)

18

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)

(x2,y2)

(x3,y3)

19

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)

(x2,y2)

(x3,y3)

20

1 32 4 5

6 7 8 9 10

11 12 13

21

Julius Tree