Recursive Methods Noter ch.2 Recursive Methods Recursive problem - - PowerPoint PPT Presentation
Recursive Methods Noter ch.2 Recursive Methods Recursive problem - - PowerPoint PPT Presentation
Recursive Methods Noter ch.2 Recursive Methods Recursive problem solution Problems that are naturally solved by recursion Examples: Recursive function: Fibonacci numbers Recursive graphics: Fractals Mutual recursion:
Recursive Methods
- Recursive problem solution
– Problems that are naturally solved by recursion
- Examples:
– Recursive function: Fibonacci numbers – Recursive graphics: Fractals – Mutual recursion: Expression evaluation – Randomization and recursion: Random plants/trees
- General aspects
– Termination – Recursion versus iteration: simplicity vs efficiency
Recursion in trees and flowers
Tree
=
3 smaller trees/branches trunk
Natural Recursion: Derivative of Rational Function
- →
QUIZ
What is the proper recursive definition of the factorial function? (Assume n ≥ 1) 1. n! = n * (n-1)! 2. n! = 3. n! = 4. n! = 5. n! = 6. None of the above 7. I don’t know
Factorial function: n! = 1 * 2 * 3 * ... * (n-1) * n (n-1)! For n > 1 1 For n = 1 (n-1)! For n > 1 n-1 For n = 1 n*(n-1)! For n > 1 1 For n = 1 n*(n-1) For n > 1 (n-1)! For n = 1 Recursive definition
Factorial function
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
n! = Java method for computing factorial function: n*(n-1)! For n > 1 1 For n ≤ 1
public static long factorial(int n) { if (n<=1) return 1; else return n*factorial(n-1); }
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3
1.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result =
1.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall =
1.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2
1.call 2.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result =
1.call 2.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = recursiveCall =
1.call 2.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = recursiveCall = 3rd call: n = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = recursiveCall = 3rd call: n = 1 result =
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = recursiveCall = 3rd call: n = 1 result = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = recursiveCall = 1 3rd call: (finished) n = 1 result = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2nd call: n = 2 result = 2 recursiveCall = 1 3rd call: (finished) n = 1 result = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = recursiveCall = 2 2nd call: (finished) n = 2 result = 2 recursiveCall = 1 3rd call: (finished) n = 1 result = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: n = 3 result = 6 recursiveCall = 2 2nd call: (finished) n = 2 result = 2 recursiveCall = 1 3rd call: (finished) n = 1 result = 1
1.call 2.call 3.call
public static long factorial(int n) { long result; if (n<=1) { result = 1; } else { long recursiveCall = factorial(n-1); result = n*recursiveCall; } return result; }
1st call: (finished) n = 3 result = 6 recursiveCall = 2 2nd call: (finished) n = 2 result = 2 recursiveCall = 1 3rd call: (finished) n = 1 result = 1
1.call 2.call 3.call
QUIZ
public static void foo(int x) { System.out.println(x); if (x>1) foo(x-1); } What is the result of the method call foo(4) ? 1. Prints 4 2. Prints 1 3. Prints 1 2 3 4 4. Prints 4 3 2 1 5. Prints something else 6. Compiler error: method foo is not allowed to call itself 7. Runtime error: method foo is not allowed to call itself 8. I don’t know Recursive method call
Recursive Function: Fibonacci Numbers
- The sequence of Fibonacci numbers is
- First 10 terms are
– 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
Recursive Function: Fibonacci Numbers
- Recursive method corresponding to recursive
definition of Fibonacci numbers
public long fib(int n) { if (n <= 1) return 1; else return fib(n - 1) + fib(n - 2); }
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 2nd call: n = 3
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 2nd call: n = 3
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 2nd call: n = 3 4th call: n = 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 2nd call: n = 3 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 2nd call: n = 3 5th call: n = 0 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 2nd call: n = 3 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 2nd call: n = 3 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 2nd call: n = 3 6th call: n = 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 2nd call: n = 3 6th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 8th call: n = 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 8th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 9th call: n = 0 8th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 9th call: n = 0 returns 1 8th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 3rd call: n = 2 returns 2 7th call: n = 2 returns 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 9th call: n = 0 returns 1 8th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Structure of method calls
public long fib(int n) { if (n<=1) return 1; else return fib(n-1) + fib(n-2); }
1st call: n = 4 returns 5 3rd call: n = 2 returns 2 7th call: n = 2 returns 2 2nd call: n = 3 returns 3 6th call: n = 1 returns 1 9th call: n = 0 returns 1 8th call: n = 1 returns 1 5th call: n = 0 returns 1 4th call: n = 1 returns 1
Tree Structure of Method Call fib(4)
Thinking recursively vs efficiency
- Recursive solution may be natural and simple to program
public long fib(int n) { if (n <= 1) return 1; else return fib(n - 1) + fib(n - 2); }
- But iterative solution may be more efficient
public long iterativeFib(int n) { if (n <= 1) return 1; long fold = 1; long fold2 = 1; long fnew = 1; for (int i = 2; i <= n; i++) { fnew = fold + fold2; fold2 = fold; fold = fnew; } return fnew; }
QUIZ
/* @precondition n>=1 */ public int area(int n) { } a) return n*(n+1)/2; b) if (n==1) return 1; else return area(n-1); c) return n+area(n-1); d) if (n==1) return 1; else return n+area(n-1); n Implement recursion Which lines should replace to
- btain a correct and recursive
computation of triangle area ? (for n=4, the area is 10) 1. a 2. b 3. c 4. d 5. None of a,b,c,d 6. More than one of a,b,c,d could be used 7. I don’t know
Recursive graphics
- The snowflake is built
from 3 Koch lines of
- rder 4.
- The Koch line is
defined recursively
Fractals: Koch lines of order 1-4
- A line of order 0 is a
straight line
- A line of order n
consists of 4 lines of
- rder n-1 each of 1/3
length
n>=1
Order n−1 Order n−1 Order n−1 Order n−1 Order
Crayon class
- State of Crayon object
– Colour – Width (pixel) – Position (coordinates) – Direction (0-360 deg)
- Public methods
– Relative changes – move(d): draw line of lenght d (from position in direction to new position) – jump(d): change position without drawing – turn(a): add a degrees to direction – Absolute changes – moveto(x,y): – jumpto(x,y): – turnto(a):
KochLineTest
public class KochLineTest { public static void main(String[] args) { c = new Crayon(Color.red,1); c.jumpto(50,150); kochLine(4,300); c.turn(120); kochLine(4,300); c.turn(120); kochLine(4,300); c.turn(120); } private static Crayon c; private static void kochLine(int order, double len) {...} }
recursive method kochLine
void kochLine(int order, double len) { if (order == 0) c.move(len); else if (order > 0) { kochLine(order-1,len/3); c.turn(-60); kochLine(order-1,len/3); c.turn(120); kochLine(order-1,len/3); c.turn(-60); kochLine(order-1,len/3); } } n>=1
Order n−1 Order n−1 Order n−1 Order n−1 Order
QUIZ
a b Sierpinski Triangle Which of these recursions can be used to draw a Sierpiski Triangle? 1. Neither 2. a 3. b 4. c 5. a+b 6. b+c 7. a+c 8. a+b+c 9. I don’t know c Order 0 Order 1
Recursion in general: Termination
- Recursive call need not terminate
public void loopingRecursiveMethod() { loopingRecursiveMethod(); }
- Any reasonable recursive method should have recursion
condition
public long fib(int n) { if (n <= 1) return 1; else return fib(n - 1) + fib(n - 2); } private void kochLine(int order, double len) { if (order == 0) no recursive call else if (order > 0) recursive call } no recursive call recursive call
Mutual Recursion and termination
- up and down are mutually recursive:
public void down(int n) { while(n%2==0) n = n/2; up(n); } public void up(int n) { if (n>1) { n = 3*n+1; down(n); } }
- It is unknown whether the call down(m) terminates for all m! (Collatz
conjecture, 1937)
- A recursion condition does not necessarily ensure termination
QUIZ
Precondition for both methods: n >= 0 public boolean even(int n) { if (n==0) return true; return odd(n-1); } public boolean odd(int n) { if (n==0) return false; return even(n-1); } Which assertions are correct? 1. Both odd and even always stops 2.
- dd always stops, but even may loop indefinitely
3. even always stops, but odd may loop indefinitely 4. Both odd and even may loop indefinitely 5. I don’t know Mutual recursion and termination
Random trees and flowers
Random trees and flowers
Recursive trees
1 leaf/branch/trunk Order 2 6 5 4 3
- leaf, branch, trunk differ by colors and thickness
Tree
=
3 smaller trees/branches trunk
Variation by randomization
- Each tree consists of a trunk and up to
BRANCH_MAX=6 smaller trees
- Each of the subtrees are drawn with probability
BRANCH_PROB=0.4
- Subtrees are tilted with angle to neighbor being
BRANCH_ANGLE=13 deg.
Order n−1 Order n−1 Order trunk Order n−1 n>=1 BRANCH_ANGLE leaf
class CCrayon
- CCrayon is a variant of Crayon with
2 extra methods:
– setColor – setWidth
class TreeTest
public class TreeTest { public static void main(String[] args) { c = new CCrayon(); c.jumpto(200,400); c.turn(-90); tree(6,40); } private static CCrayon c; private static void tree(int order, int len) {...} private static void leaf(int len) { ... } private final static int BRANCH_MAX = 6; private final static int BRANCH_ANGLE = 13; private final static double BRANCH_PROB = 0.4; private final static double LEAF_PROB = 0.3; }
Recursive method tree
public void tree(int order, int len) { if (order==0) leaf(len/2); else { int bias = (int) (2*Math.random()); if (order+bias >=6) c.setColor(Color.black); else if (order+bias >=4) c.setColor(Color.gray); else c.setColor(Color.green); c.setWidth(2*order); c.move(len); c.turn((BRANCH_ANGLE*(BRANCH_MAX-1))/2.0); for (int i = 1 ; i<=BRANCH_MAX ; i = i+1 ) { if (Math.random()<BRANCH_PROB) tree(order-1, len-2); c.turn(-BRANCH_ANGLE); } c.turn((BRANCH_ANGLE*(BRANCH_MAX+1))/2.0); c.turn(180); c.jump(len); c.turn(-180); //return pen to base of tree } }
Method leaf
void leaf(int len) { if (Math.random()<LEAF_PROB) { if (Math.random()<0.5) c.setColor(Color.red); else c.setColor(Color.yellow); c.setWidth(2); c.turn(-BRANCH_ANGLE/2.0); c.move(len); c.turn(BRANCH_ANGLE); c.move(len); c.turn(180-BRANCH_ANGLE); c.move(len); c.turn(BRANCH_ANGLE); c.move(len); c.turn(180-BRANCH_ANGLE/2.0); } }