Download Recursion - Object-Oriented Programming and Data Structures - Lecture Sl and more Lecture notes Object Oriented Programming in PDF only on Docsity! Recursion • Arises in three forms in computer science – Recursion as a mathematical tool for defining a function in terms of its own value in a simpler case – Recursion as a programming tool. You’ve seen this previously but we’ll take it to mind‐bending extremes (by the end of the class it will seem easy!) – Recursion used to prove properties about algorithms. We use the term induction for this and will discuss it later. docsity.com Recursion as a math technique • Broadly, recursion is a powerful technique for specifying functions, sets, and programs • A few recursively‐defined functions and programs – factorial – combinations – exponentiation (raising to an integer power) • Some recursively‐defined sets – grammars – expressions – data structures (lists, trees, ...) docsity.com Count the e’s in a string • countEm(‘e’, “it is easy to see that this has many e’s”) = 4 • countEm(‘e’, “Mississippi”) = 0 /** = " number of times c occurs in s */ public static int countEm(char c, String s) { if (s.length() == 0) return 0; // { s has at least 1 character } if (s.charAt(0) != c) return countEm(c, s.substring(1)); // { first character of s is c} return 1 + countEm (c, s.substring(1)); } Substring from char(1) to end docsity.com The Factorial Function (n!)
* Define n! = n-(n—1):(n—2)---3-2-1
read: “n factorial”
—E.g., 3!=3-21=6
¢ By convention, 0! =1
¢ The function int — int that gives n! on
input n is called the factorial function
® docsity.com
The Factorial Function (n!) • n! is the number of permutations of n distinct objects – There is just one permutation of one object. 1! = 1 – There are two permutations of two objects: 2! = 2 1 2 2 1 – There are six permutations of three objects: 3! = 6 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 • If n > 0, n! = n∙(n 1)! docsity.com A Recursive Program static int fact(int n) { if (n = = 0) return 1; else return n*fact(n-1); } 0! = 1 n! = n·(n1)!, n > 0 1 1 2 6 Execution of fact(4) fact(1) fact(4) fact(3) fact(0) fact(2) 24 docsity.com General Approach to Writing Recursive Functions 1. Try to find a parameter, say n, such that the solution for n can be obtained by combining solutions to the same problem using smaller values of n (e.g., (n‐1) in our factorial example) 2. Find base case(s) – small values of n for which you can just write down the solution (e.g., 0! = 1) 3. Verify that, for any valid value of n, applying the reduction of step 1 repeatedly will ultimately hit one of the base cases docsity.com A cautionary note • Keep in mind that each instance of your recursive function has its own local variables • Also, remember that “higher” instances are waiting while “lower” instances run • Not such a good idea to touch global variables from within recursive functions – Legal… but a common source of errors – Must have a really clear mental picture of how recursion is performed to get this right! docsity.com One thing to notice • This way of computing the Fibonacci function is elegant, but inefficient • It “recomputes” answers again and again! • To improve speed, need to save known answers in a table! – One entry per answer – Such a table is called a cache fib(4) fib(2) fib(0) fib(1) fib(3) fib(0) fib(1) fib(1) fib(2) docsity.com Memoization (fancy term for “caching”) • Memoization is an optimization technique used to speed up computer programs by having function calls avoid repeating the calculation of results for previously processed inputs. – The first time the function is called, we save result – The next time, we can look the result up • Assumes a “side effect free” function: The function just computes the result, it doesn’t change things • If the function depends on anything that changes, must “empty” the saved results list docsity.com Adding Memoization to our solution • Before: • After static int fib(int n) { if (n == 0) return 0; else if (n == 1) return 1; else return fib(n-2) + fib(n-1); } static ArrayList<Integer> cached = new ArrayList<Integer>(); static int fib(int n) { if(n < cached.size()) return cached.get(n); int v; if (n == 0) v = 0; else if (n == 1) v = 1; else v = fib(n-2) + fib(n-1); // cached[n] = fib(n). This code makes use of the fact // that an ArrayList adds elements to the end of the list if(n == cached.size()) cached.add(v); return v; } docsity.com Positive Integer Powers • an = a∙a∙a∙∙∙a (n times) • Alternate description: – a0 = 1 – an+1 = a∙an static int power(int a, int n) { if (n == 0) return 1; else return a*power(a,n-1); } docsity.com A Smarter Version • Power computation: – a0 = 1 – If n is nonzero and even, an = (an/2)2 – If n is odd, an = a∙(an/2)2 • Java note: If x and y are integers, “x/y” returns the integer part of the quotient • Example: – a5 = a∙(a5/2)2 = a∙(a2)2 = a∙((a2/2)2)2 = a∙(a2)2 Note: this requires 3 multiplications rather than 5! docsity.com A Smarter Version • … Example: – a5 = a∙(a5/2)2 = a∙(a2)2 = a∙((a2/2)2)2 = a∙(a2)2 Note: this requires 3 multiplications rather than 5! • What if n were larger? – Savings would be more significant • This is much faster than the straightforward computation – Straightforward computation: n multiplications – Smarter computation: log(n) multiplications docsity.com Stacks • Like a stack of dinner plates • You can push data on top or pop data off the top in a LIFO (last‐in‐first‐out) fashion • A queue is similar, except it is FIFO (first‐in‐first‐out) top element 2nd element 3rd element ... bottom element ... top-of-stack pointer stack grows docsity.com return info local variables parameters Stack Frame • A new stack frame is pushed with each recursive call • The stack frame is popped when the method returns – Leaving a return value (if there is one) on top of the stack a stack frame retval halfPower a, n docsity.com Example: power(2, 5) return info (a = ) 2 (n = ) 5 (hP = ) ? return info (a = ) 2 (n = ) 5 (hP = ) ? return info (a = ) 2 (n = ) 2 (hP = ) ? return info (a = ) 2 (n = ) 5 (hP = ) ? return info (a = ) 2 (n = ) 2 (hP = ) ? return info (a = ) 2 (n = ) 1 (hP = ) ? return info (a = ) 2 (n = ) 5 (hP = ) 4 return info (a = ) 2 (n = ) 5 (hP = ) ? return info (a = ) 2 (n = ) 2 (hP = ) 2 return info (a = ) 2 (n = ) 5 (hP = ) ? return info (a = ) 2 (n = ) 2 (hP = ) ? return info (a = ) 2 (n = ) 1 (hP = ) 1 (retval = ) 1 (retval = ) 2 (retval = ) 4 (retval = ) 32 hP: short for halfPower docsity.com Extra slides
¢ For use if we have time for one more example
of recursion
¢ This builds on the ideas in the Fibonacci
example
docsity.com
Combinations (a.k.a. Binomial Coefficients) • How many ways can you choose r items from a set of n distinct elements? ( ) “n choose r” ( ) = number of 2‐element subsets of {A,B,C,D,E} 2‐element subsets containing A: {A,B}, {A,C}, {A,D}, {A,E} 2‐element subsets not containing A: {B,C},{B,D},{B,E},{C,D},{C,E},{D,E} • Therefore, = + • … in perfect form to write a recursive function! ( ) 4 1 ( ) 4 2 ( ) 4 1 ( ) 4 2 ( ) 5 2 n r 5 2 docsity.com Combinations = + , n > r > 0 = 1 = 1 ( ) n r ( ) n1 r ( ) n1 r1 ( )n n ( )n 0 ( ) 0 0 ( ) 1 1 ( ) 1 0 ( ) 2 2 ( ) 2 1 ( ) 2 0 ( ) 3 3 ( ) 3 2 ( ) 3 1 ( ) 3 0 ( ) 4 4 ( ) 4 3 ( ) 4 2 ( ) 4 1 ( ) 4 0 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 = Pascal’s triangle Can also show that = ( )n r n! r!(nr)! docsity.com Recursive Program for Combinations static int combs(int n, int r) { //assume n>=r>=0 if (r == 0 || r == n) return 1; //base cases else return combs(n-1,r) + combs(n-1,r-1); } = + , n > r > 0 = 1 = 1 ( ) n r ( ) n1 r ( )n1 r1 ( )n n ( )n 0 docsity.com Exercise for the reader (you!) • Modify our recursive program so that it caches results • Same idea as for our caching version of the fibonacci series • Question to ponder: When is it worthwhile to adding caching to a recursive function? – Certainly not always… – Must think about tradeoffs: space to maintain the cached results vs speedup obtained by having them docsity.com Something to think about • With fib(), it was kind of a trick to arrange that: cached[n]=fib(n) • Caching combinatorial values will force you to store more than just the answer: – Create a class called Triple – Design it to have integer fields n, r, v – Store Triple objects into ArrayList<Triple> cached; – Search cached for a saved value matching n and r • Hint: use a foreach loop docsity.com