1 / 29

Data Structures and Algorithms for Information Processing

Data Structures and Algorithms for Information Processing. Some Notes on Recursion. Recursion. We’ve seen several examples of the use of recursion We’ll take a closer look at recursion as a style of programming Lends itself to analytical methods; proving program properties.

prema
Download Presentation

Data Structures and Algorithms for Information Processing

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Data Structures and Algorithms for Information Processing Some Notes on Recursion Some Notes on Recursion

  2. Recursion • We’ve seen several examples of the use of recursion • We’ll take a closer look at recursion as a style of programming • Lends itself to analytical methods; proving program properties Some Notes on Recursion

  3. Verifying Program Properties • How can we be sure that a program is correct? • Debug • Test cases • Make sure output matches another program • ... • None of these give absolute assurance Some Notes on Recursion

  4. Imperative Programming • The “usual” style in Java, using commands • Programs are written by create data (“state”) and storing it in variables • Flow of control insures that correct sequence of assignments is executed Some Notes on Recursion

  5. Applicative Programming • No references to other objects • No side effects (assignments, output...) • Some advantages: • Functions only return values • No need for loops • Easier to prove properties • A different programming style, and a different way to think about programming Some Notes on Recursion

  6. Recursion • General pattern: recursive_fn(params) { if (…) return some_value; else ... recursive_fn(new_params) ... } • A recursive function call is made somewhere in the body of the function Some Notes on Recursion

  7. Tail Recursion • General pattern: tail_recursive_fn(params) { if (…) return some_value; else return tail_recursive_fn(new_params) } • Tail recursive: the function does no work after the recursive call Some Notes on Recursion

  8. Tail Recursion • “Usual” recursive factorial // Precondition: n >= 0 static int fact1(int n) { if (n==0) return 1; else return n*fact1(n-1); } Some Notes on Recursion

  9. Tail Recursion • Tail recursive factorial static int fact2(int n) { // Precondition: n >= 0 return fact2_aux(n, 1); } static int fact2_aux(int n, int accum) { if (n==0) return accum; else return fact2_aux(n-1, n*accum); } Some Notes on Recursion

  10. Execution Trace fact1(5) 5*fact1(4) 5*4*fact1(3) 5*4*3*fact1(2) 5*4*3*2*fact1(1) 5*4*3*2*1*fact1(0) 5*4*3*2*1*1 => 120 Some Notes on Recursion

  11. Execution Trace fact2(5) fact2_aux(5,1) fact2_aux(4,5) fact2_aux(3,20) fact2_aux(2,60) fact2_aux(1,120) fact2_aux(0,120) => 120 Some Notes on Recursion

  12. Example of Non-Tail Recursion // Precondition: y > 0 static int mult (int x, int y) { if (y==1) return x; else return x + mult(x, y-1); } • Addition operation carried out after the recursive call Some Notes on Recursion

  13. Tail Recursion (cont) • Tail recursive functions can be more efficient • Often easier to prove properties of tail recursive functions • correctness, termination, cost • technique: induction Some Notes on Recursion

  14. Example: fact2 Want to prove using induction that fact2(n) => n! • We do this by proving an appropriate property of the auxiliary function: fact2_aux(n, p) => n! * p Some Notes on Recursion

  15. Example: fact2 (cont) • Base case: n=0 • for all p fact2_aux(0, p) => p = 0! * p • Inductive step: n > 0: • Assume true for n-1 • For all p fact2_aux(n-1, p) =>(n-1)! * p Some Notes on Recursion

  16. Example: fact2 (cont) • Inductive step: n > 0: • Assume true for n-1 • For all p fact2_aux(n-1, p) =>(n-1)! * p • So: fact2_aux(n, p) => fact2_aux(n-1, n*p) => (n-1)! * (n*p) = (n*(n-1)!)*p = n!*p Some Notes on Recursion

  17. Example: fact2 (cont) • Proving termination by induction: • Base case: fact2_aux(0, p) => return p • Inductive case: terminates if operator * terminates Some Notes on Recursion

  18. Tail recursive reverse • We can easily get an O(n) implementation using tail recursion: List rev2_aux(List x, List y) { if (x==null) return y; else return rev2_aux(x.next(), new List(x.value(), y)) } List reverse2(x) { return rev2_aux(x, null); } Some Notes on Recursion

  19. Cost of rev2_aux • Let Cost[n,m] be the number of operations for rev2_aux(x,y) with x.length()=n and y.length() = m • Cost[0,m] = A (constant) • n>0, Cost[n,m] = Cost[n-1,m+1] + B • Thus, Cost[n,m] = A + nB = O(n) Some Notes on Recursion

  20. Fibonacci Numbers • Want fib(0)=1, fib(1)=1, fib(n) = fib(n-1) + fib(n-2) if n>1 • Simple recursive implementation: // Precondition: n>=0 int fib(int n) { if (n < 2) return 1; else return fib(n-1)+fib(n-2); } Some Notes on Recursion

  21. Fibonacci Numbers • Cost is the same as the Fibonacci numbers themselves! • fib(n) rises exponentially with n: • fib(n) > (1.618)^n / 2 Some Notes on Recursion

  22. Imperative version int i=1; int a=1, b=1; while (i<n) { int c = a+b; // fib(i+1) a = b; b = c; i++; } Some Notes on Recursion

  23. Recursive Version • Define an auxiliary function fib_aux • Use two accumulator variables, one set to fib(i-1), the other to fib(i) Some Notes on Recursion

  24. Recursive Version int fib_aux (int n, int i, int x, int y) { if (i==n) return y; else return fib_aux(n, i+1, y, x+y); } int fib(int n) { if (n==0) return 1; else return fib_aux(n, 1, 1, 1); } Some Notes on Recursion

  25. Backtracking Search General pattern: • Test if current position satisfies goal • If not, mark current position as visited and make a recursive call to search procedure on neighboring points • Exhaustive search, terminates as soon as goal is found Some Notes on Recursion

  26. Backtracking search: simple example The “bear game”: • Start with initial number of bears • Need to reach goal number within a certain number of steps • Possible moves: • Add incr number of bears • If even divide current number in half • Suppose initial=10, goal=100, incr=50,n=5 Some Notes on Recursion

  27. Backtracking search: simple example Public static boolean bears (int initial, int goal, int incr, int n) { if (initial == goal) return true; else if (n==0) return false; else if (bears(initial+incr, goal, incr, n-1)) return true; else if (initial % 2 == 0) return bears(initial/2, goal, incr, n-1); else return false; } Some Notes on Recursion

  28. Backtracking search: simple example • Why does this program terminate? • What if we remove the restriction on the number of steps? Some Notes on Recursion

  29. Benefits of Recursion • Recursion can often be implemented efficiently • Requires less work (programming and computation) • Tail recursive versions require less stack space • The code is typically much cleaner than imperative versions Some Notes on Recursion

More Related