1 / 42

Recursion

Recursion. Joe Meehean. Recursive Methods. void g(){ ... h(); ... } void h(){ ... g(); ... }. void f(){ ... f(); ... }. call themselves directly or indirectly. Recursive Method Example. int factorial( int x){ int handback ; if( x <= 1 ){ handback = 1;

zalman
Download Presentation

Recursion

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. Recursion Joe Meehean

  2. Recursive Methods void g(){ ... h(); ... } void h(){ ... g(); ... } void f(){ ... f(); ... } • call themselves directly • or indirectly

  3. Recursive Method Example int factorial(int x){ inthandback; if( x <= 1 ){ handback = 1; }else{ handback = x * factorial(x-1); } return handback; } factorial(4) = 4 * factorial(4 – 1) factorial(3) = 3 * factorial(3 – 1) … factorial(1) = 1

  4. Conceptual Recursion • When a recursive call is made: • marks current place in code • clones itself • copy of code • new parameters • new set of uninitialized local variables • clone executes starting at beginning • When clone returns • clone is cleaned up • previous version starts at just afterrecursive method call

  5. CLASS ACTIVITY void doClap(int k){ if(k == 0 ) return; clap k times; doClap(k – 1); return; } 1st person: doClap(3)

  6. Incorrect Recursion void doClap(int k){ clap k times; doClap(k + 1); return; } • doClap(3) • 3, 4, 5, 6, … • memory access error • need code to stop recursion eventually

  7. Recursion Rule 1 void doClap(int k){ if( k == 0 ) return; clap k times; doClap(k + 1); return; } • Still has infinite recursion? • Must have a base case • Condition under which no recursive call is made • Helps prevent infinite recursion

  8. Recursion Rule 2 void doClap(int k){ if( k == 0 ) return; clap k times; doClap(k - 1); return; } • Does doClap follow rules 1 & 2? • Infinite recursion? • If so, how should we change the code Must make progress towards base case

  9. Recursion Rule 2 void doClap(int k){ if( k <= 0 ) return; clap k times; doClap(k - 1); return; } • Does doClap follow rules 1 & 2? • Infinite recursion? • If so, how should we change the code Must make progress towards base case

  10. Another Example void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k]; printStr(s, k+1); } printStr(“hello”, 0) => “hello” printStr(“hello”, 2) => “llo”

  11. Recursion Rule 3 void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k]; printStr(s, k+1); } • Design rule • assume that all recursive calls work • even if you haven’t finished writing it yet

  12. Another Example void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k] << endl; printStr(s, k+1); } printStr(“hello”, 0) h printStr(“hello”, 1) e printStr(“hello”, 2) l printStr(“hello”, 3) l printStr(“hello”, 4) o printStr(“hello”, 5)

  13. Another Example void printStr(string s, int k){ if( k >= s.length() ) return; printStr(s, k+1); cout << s[k] << endl; } printStr(“hello”, 0) h printStr(“hello”, 1) e printStr(“hello”, 2) l printStr(“hello”, 3) l printStr(“hello”, 4) o printStr(“hello”, 5)

  14. Understanding Recursion • A method may have statements • before recursive call • after recursive • both • After statements are done only • when the recursive call is finished • and all the recursive calls recursive calls have finished

  15. DISCUSSION BREAK!!! void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k] << endl; printStr(s, k+1); cout << s[k] << endl; } Whats printed for printStr(“STOP, 0)?

  16. DISCUSSION BREAK!!! void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k] << endl; printStr(s, k+1); cout << s[k] << endl; } • Whats printed for printStr(“STOP, 0)? • STOPPOTS • How can we change it to print • STOP<BREAK>POTS

  17. DISCUSSION BREAK!!! void printStr(string s, int k){ if( k >= s.length() ){ cout << “<BREAK>” << endl; return; } cout << s[k] << endl; printStr(s, k+1); cout << s[k] << endl; } • How can we change it to print • STOP<BREAK>POTS

  18. Questions?

  19. Local Variables void mystery(int j){ if( j <= 0 ) return; intk = j * 2; mystery(j – 1); cout << k << “ “; } • Each clone gets own local variables • Outputs => 2 4 6

  20. Recursive Call in Expressions // sums #s from 1 to max // Iterative version intdoSum(int max){ int sum = 0; for(inti = 1; i <= max; i++){ sum += i; } return sum; }

  21. Recursive Call in Expressions // sums #s from 1 to max // Iterative version intdoSum(int max){ int sum = 0; for(inti = 1; i <= max; i++){ sum += i; } return sum; } // Recursive version intdoSum(int max){ if( max <= 0 ) return 0; return max + doSum(max – 1); }

  22. Recursive Call in Expressions doSum(3) + 3 doSum(2) + 2 doSum(1) + 1 doSum(0)

  23. Recursion in Practice • Can do recursion with int parameters • count up or down to base case • Or, with recursive data structures • a linked list is either empty • or a node followed by a linked list

  24. Recursion in Practice void printList(Node<T> *node){ if( node == NULL ) return; cout << node->data << endl; printList(node->next); } Prints list in order

  25. DISCUSSION BREAK!!! void printList(Node<T> *node){ if( node == NULL ) return; cout<< node->data << endl; printList(node->next); } How can we change this code to print list backwards?

  26. DISCUSSION BREAK!!! void printList(Node<T> *node){ if( node == NULL ) return; printList(node->next); cout << node->data << endl; } Prints list backwards Rare case where recursion makes code faster as well as simpler

  27. How does recursion really work? • Activation records (ARs) • stack of ARs maintained at runtime • 1 AR for each active method • active methods have been called, but not returned yet • Each AR includes: • function parameters • local variables • return address

  28. How does recursion really work? • Activation Record Stack • when method is called, its AR is pushed • when method returns, its AR is popped • return address in popped AR tells program where to return control flow

  29. Recursion Examples • Auxiliary recursion • wrapper method to do something ONCE before or after recursion • OR pass more parameters • recursion in auxiliary method • wrapper sometimes called a driver • Multiple recursive calls per method • need to recurse down a few different paths • more on this when we talks about trees

  30. Example 1 // prints a header and the endline // calls aux to print the list void printList(Node<T> *node){ cout << “The list contains: “; printAux(node); cout << endl; } // prints a single string containing // each element in brackets void printAux(Node<T>* node){ if( node == NULL ) return; cout << “[“ << node->data << “]”; printAux(node->next); }

  31. Example 2 // public method calls private method // with member variable int List::numNodes(){ return numAux(phead_); } // actually counts the nodes int List::numAux(Node<T>* node){ if( node == NULL ){ return 0; } return 1 + numAux(node->next); }

  32. Example 3: Extra parameters intweirdSum(vector<int>& intVect){ return sumVector(intVect, 1); } // actually sums the entries intsumVector( vector<int>& intVect, intpos){ if( pos >= intVect.size() ) return 0; return intVect[pos] + sumAux(intVect, pos + 1); } Sum all elements in a vector but the first value

  33. Example 4: Multi-recursive calls int fib(int n){ if( n <= 2) return 1; return fib(n – 2) + fib(n – 1); } • Fibonacci • fib(1) = 1, fib(2) = 1 • fib(N) for N > 2 = fib(N-1) + fib(N-2) • fib(3) = fib(2) + fib(1) = 1 + 1 = 2

  34. Fibonacci Call Trace fib(4) 3 + 1 2 fib(3) fib(2) 2 + 1 1 fib(1) fib(2) Note: fib(2) is called twice Redoing work

  35. Recursion Rule 4 • Compound interest rule • Never duplicate work • don’t solve the same recursive instance in separate recursive calls • repeats work you’ve already done • more on how to prevent this in CS242

  36. Questions?

  37. What good is it? • Recursion DOES NOT make your code faster • Recursion DOES NOT use less memory • Recursion DOES make your code simpler • sometimes

  38. When is it a bad idea? • When you don’t get anything from it? • Tail recursion • the only recursive call is the last line • local variables stored just to be thrown away • Tail recursion can be replaced with a while loop

  39. When is it a bad idea? void printStr(string s, int k){ if( k >= s.length() ) return; cout << s[k] << endl; printStr(s, k+1); } void printStrin(string s, int k){ while( true ){ if( k >= s.length() ) return; cout<< s[k] << endl; k = k + 1; } }

  40. When is it a bad idea? void printString(string s, int k){ while( k < s.length()){ cout<< s[k] << endl; k = k + 1; } }

  41. Recursion Rules Recap Base case Make progress Design rule Compound interest rule

  42. Questions?

More Related