240 likes | 734 Views
Session 05: C# Recursion. Factorial Recursion stack Binary Search Towers of Hanoi. Recursion. In programming languages recursion is when a method is calling it self (recursion may be indirectly) Recursion often comes around when a problem can be solved using a divide and conquer strategy:
E N D
Session 05:C# Recursion Factorial Recursion stack Binary Search Towers of Hanoi AK IT: Softwarekonstruktion
Recursion • In programming languages recursion is when a method is calling it self (recursion may be indirectly) • Recursion often comes around when a problem can be solved using a divide and conquer strategy: • If the problem is small, we can apply some simple (non-recursive) solution. (called “base case”) • Otherwise the problem is divided into smaller sub problems of the same kind. The sub problems are then solved by applying the solution recursively to the sub problems. • Eventually the sub problems become so small that the simple solution can be applied, and recursion terminates. • When the sub problems are solved, the solutions to the sub problems are combined into a solution to the original problem. AK IT: Softwarekonstruktion
Recursion –Divide and Conquer • Divide: • If the problem is small, we can apply some simple (non-recursive) solution (called “base case”). • Otherwise the problem is divided into smaller sub problems of the same kind. The sub problems are then solved by applying the solution recursively to the sub problems. • Eventually the sub problems become so small that the simple solution can be applied, and recursion terminates. • Note the similarities to loops • Conquer: • Simple sub problems are solved using the non-recursive solution • When the sub problems are solved, the solutions to the sub problems are combined into a solution to the original problem. AK IT: Softwarekonstruktion
Example • Many mathematical functions may be defined recursively. For instance, computing the factorial of an number n (n!): n! = n * (n-1)! for n > 0 n! = 1 for n = 0 • The base case (simple problem) is when n=0 • If n>0 the problem is divided into the subproblem of computing the factorial of n-1 • The combine part is multiplying the result of (n-1)! by n. Note: There must be a base case, so recursion eventually stops. AK IT: Softwarekonstruktion
RecursiveFactorial in C# publicstaticlongFac(long n) { calls++; if (n == 0) return 1; else return n * Fac(n - 1); } AK IT: Softwarekonstruktion
Stack: top Behind the Scenes:The Recursion Stack • When a recursive method executes many activations of the method exist at the same time. • The virtual machine is handling this by storing the different states of the method on a stack: • Value of parameters and local variables • Return address • When a method is called, an activation is created and pushed onto the stack • When a method returns, its activation is popped from the stack • The current activation of the method is always the topmost on the stack, and it is the values of parameters, local variables etc. stored that is used. • A stack is a list, where insert (push) and remove (pop) are done at the front of the list (stack top). AK IT: Softwarekonstruktion
Iterative Factorial • Actual it is not very smart to compute the factorial of n recursively – a loop can do the job much more efficiently: public long FacIter(int n) { long fac = 1; for (inti = 2; i <= n; i++) fac = fac * i; return fac; } But is it more simple? public long Fac(intn) if (n == 0 || n == 1) return 1; else return n * Fac(n-1); } AK IT: Softwarekonstruktion
Exercise • Write a recursive method that computes the sum of the first n non-negative numbers. • Hint: the sum may be define by: • sum(n) = n + sum(n-1) for n > 0 sum(n) = 0 for n = 0 • Draw pictures of the recursion stack when sum(3) is computed AK IT: Softwarekonstruktion
Binary Search • In a sorted random access (array based) data set it is possible to use binary search. • Binary search can be formulated very simply using recursion: • Strategy: If - the search set is empty Then - the searched element, s, is not in the set Else - inspect the middle element, m - If - m == s - Then - the element is found and we are done - Else - If - m > s - Then - search in the lower half of the set - Else - search in the upper half of the set Note the recursive nature of this solution! AK IT: Softwarekonstruktion
In C#… publicstaticboolBinSearch(int l, int h, int x, int[] T) { //PRE T is sorted //Looking for x between l and h in T calls++; int m; if (l > h) returnfalse; else { m = (l + h) / 2; if (x == T[m]) returntrue; else if (x > T[m]) returnBinSearch(m + 1, h, x, T); else returnBinSearch(l, m - 1, x, T); } } AK IT: Softwarekonstruktion
The Towers of Hanoi • Three pins: • source, S • target, T • help, H • 64 discs with decreasing diameters are to be moved from S to T observing the following rules: • A larger disc can not be placed upon a smaller • Only one disc can be moved at the time Algorithm? AK IT: Softwarekonstruktion
The Towers of Hanoi • Solution: • Move 63 discs from S to H using T as help • Move one disc from S to T • Move 63 discs from H to T using S as help • Now the problem is how to move the 63 discs. That must be easier: • Move 62 discs… • Move one disc • Move 62 discs… This yields a recursive solution AK IT: Softwarekonstruktion
The Algorithm in C# publicstaticvoid Hanoi(int n, char s, char h, char d) { //Moves n disks from S(ource) to D(estination) using H(elp) //Do not try this for n much larger 16 calls++; if(n == 1) { //System.Console.WriteLine("Move one disk from: " + s + " to:" + d); } else { Hanoi(n - 1, s, d, h); //System.Console.WriteLine("Move one disk from: " + s + " to:" + d); Hanoi(n - 1, h, s, d); } } AK IT: Softwarekonstruktion
Efficiency of Recursive Algorithms • Overhead in time due to call-return • Overhead in space due to the recursion stack • The Recursion Tree tells about complexity: • The depth tells about memory space • The number of nodes tells about running time AK IT: Softwarekonstruktion
Examples • Draw the recursion trees: • Binary Search: O(log n) (time and space) • Factorial of n: O(n) (time and space) • Towers of Hanoi: O(2n) (time) O(n) (space) AK IT: Softwarekonstruktion
Recursive vs. Iterative Algorithms • It is always possible to rewrite a recursive algorithm to an equivalent iterative which may be more efficient. But the iterative version is often more complicated, since one has to handle the recursion stack oneself. • In some cases it is possible to find iterative algorithms that are more efficient and as simple as the equivalent recursive: • Tail recursion: • If the recursive call is the last statement in the algorithm, then there is no need for remembering the state of other active calls. • The recursion can the be converted to a loop and there is no need for the recursion stack. • Hence we get rid of the overhead to call-return and the overhead in space as well. AK IT: Softwarekonstruktion