# Recursion CS 367 – Introduction to Data Structures.

## Presentation on theme: "Recursion CS 367 – Introduction to Data Structures."— Presentation transcript:

Recursion CS 367 – Introduction to Data Structures

Definition Mathematically –a recursive function is one that is defined in terms of an absolute case and itself –example n = 1n = 0 n*(n-1)!n > 0 Consider n = 3: nresult 0!1 1!1 * 0! = 1 2!2 * 1! = 2 3!3 * 2! = 6

Definition Programming –a recursive function is one that knows the answer to a specific case; in all other cases, the function calls itself again –example int factorial(int n) { if(n == 0) return 1; else return n * factorial(n – 1); }

Function Call To understand recursion, we need a better idea of what happens on a function call –remember the program stack? on a function call, the compiler creates an activation record –parameters passed in –local variables –return address –return value (where applicable) activation record gets pushed on the program stack

Activation Records main() f1() f2() f3() return value return address local variables parameters return value return address local variables parameters return value return address local variables parameters

Calling a Function The program compiler takes care of building the activation record for each function –this means you don’t have to worry about writing it –it also means that a single function call is really a lot more code than you think this means it takes awhile to do

Calling a Function High level code void main() { int z = double(5); } int double(int x) { int y = x * 2; return y; } Compiler code # main ld r1, 5 push addr push r1 jmp # double # double pop r2 mult r3, r2, 2 pop r2 push r3 jmp r2

Calling a Function The previous compiler code is very incomplete (and not quite correct either ) Previous code does prove a point –calling a function requires more memory must create and store the activation record –calling a function takes more time must run extra code to build the activation record Fastest program would be one that only had a main function –this is very unrealistic – why? –if it were easy to do, still would be a bad idea – why?

Anatomy of a Recursive Call Consider the factorial example used earlier int factorial(int n) { if(n == 0) { return 1; } else { return n * factorial(n-1); } } Now consider the following code for main() void main() { int f = factorial(3); print(f); }

Anatomy of a Recursive Call main() factorial(3) n = 3 ret = 3 * f2 f = f1() main() factorial(2) n = 3 ret = 3 * f2 f1() n = 2 ret = 2 * f3 f2() main() factorial(1) n = 3 ret = 3 * f2 f1() n = 2 ret = 2 * f3 f2() n = 1 ret = 1 * f4 f3() main() factorial(0) n = 3 ret = 3 * f1() n = 2 ret = 2 * f2() n = 1 ret = 1 * f3() n = 0 ret = 1 f3() main() return n = 3 ret = 3 * f2 f1() n = 2 ret = 2 * f3 f2() n = 1 ret = 1 * 1 f3() main() return n = 3 ret = 3 * f2 f1() n = 2 ret = 2 * 1 f2() f = main() return n = 3 ret = 3 * 2 f1() f =

Anatomy of a Recursive Call Obviously, the last step in the previous example is missing (not enough room) –f1 will return 6 and the value (f) in main will be equal to 6 Major point –using recursion can get very expensive consume lots of memory execute a lot of extra instructions –what is the alternative?

Loops Almost any recursive function can be re- written as a loop –a loop will be much less time consuming no extra activation records to construct and store –consider the factorial example one last time int factorial(int n) { int sum = 1; for(int i=1; i<=n; i++) sum *= i; return sum; }

Loops Notice no function calls inside this version of factorial() –will run much faster than the recursive version Why use recursion? –in some cases it is easier to understand and write a recursive function

Reverse() Consider a function that prints a string of characters in the reverse order –ABC will be printed out as CBA void reverse() { char ch = getChar(); if(ch != ‘\n’) { reverse(); System.out.println(ch); }

Reverse() Note that this recursive function doesn’t return anything –simply reads a character and waits to print it until the one after it is printed very easy to understand very quick to program –how would you convert this to an iterative solution?

Reverse() Sol’n in Java void reverse() { String stack = new String(); stack = buffer.readLine(); for(top=stack.length()-1; top>=0; top--) System.out.print(stack.charAt(top)); } Sol’n in C/C++ void reverse() { char stack[80]; int top=0; stack[top] = getch(); while(stack[top] != ‘\n’) stack[++top] = getch(); for(top -= 1; top >= 0; top--) System.out.print(stack[top]); }

Reverse() Iterative sol’n must first read whole string into memory –then it can use a loop to print the string out –Java sol’n looks so simple because of the String.length() operator it tells us exactly how long the string is many languages don’t have this feature There are fewer steps and less code in the recursive sol’n –because we’re interacting with I/O, recursive nature isn’t such a big deal why?

Backtracing One of the best uses of recursion is in navigating a large, directed search space –in other words, if you are at a certain point, P, in the search space, you need to pick the next spot to search if you go in one direction, you can only go back the other direction by first returning to point P –examples finding a path from one city to another 8 queens example best move in a game searching through a tree data structure (next week)

Finding a Path Consider the graph of flights from the lecture on stacks PRXQ W YZST Key : city (represented as C) : flight from city C 1 to city C 2 C 1 C 2 flight goes from W to S W S Example

Finding a Path We showed how to use a stack to find a route from P to Y We can also do it using recursion public boolean findPath(City origin, City destination) { // pick a possible city to go to – make that city the origin if(findPath(nextCity, destination)) // found the city else // that path didn’t work, try another one } The above recursive sol’n is still going to need some kind of loop inside it –have to check all the possible routes from a city