recursive methods
play

Recursive Methods Recursive problem solution Problems that are - PDF document

Recursive Methods Recursive problem solution Problems that are naturally solved by recursion Derivative of rational function Recursive Methods Examples: Recursive function: Fibonacci numbers Recursive graphics:


  1. Recursive Methods • Recursive problem solution – Problems that are naturally solved by recursion – Derivative of rational function Recursive Methods • Examples: – Recursive function: Fibonacci numbers – Recursive graphics: Fractals – Mutual recursion: Expression evaluation Noter ch.2 – Randomization and recursion: Random plants/trees • General aspects – Termination – Recursion versus iteration: simplicity vs efficiency Natural Recursion: Recursive Function: Derivative of Rational Function Fibonacci Numbers • The sequence of Fibonacci numbers is • First 10 terms are – 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 Recursive method calls itself Recursive Function: Tree Structure of Method Call fib(4) 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); }

  2. Recursive graphics Fractals: Koch lines of order 1-4 • The snowflake is built • A line of order 0 is a from 3 Koch lines of straight line order 4. • A line of order n • The Koch line is consists of 4 lines of defined recursively order 3 each of 1/3 length Order 0 Order n−1 Order n−1 n>=1 Order n−1 Order n−1 Extending Crayon SnowFlakeCrayon public class SnowflakeCrayon extends Crayon { • Crayon class public SnowflakeCrayon(Color c, double w) { – dIntProg-opgaver 1.2.1 super(c,w); • class SnowFlakeCrayon will inherit all } the Crayon methods, and get one new public void snowflake(int order , int len) { method: kochLine( order ,len); turn(120); kochLine( order ,len); turn(120); public void snowflake(int order, int len) {...} kochLine( order ,len); turn(120); • Application: } SnowflakeCrayon c = new SnowflakeCrayon(Color.red,1); private void kochLine(int order , double len) {...} c.jumpto(50,150); } c.snowflake(4,300); recursive method kochLine Mutual Recursion private void kochLine(int order, double len) { • op and ned are mutually recursive: if (order == 0) move(len); else if (order > 0) { public void ned(int n) { kochLine(order-1,len/3); turn(-60); while(n%2==0) n = n/2; kochLine(order-1,len/3); turn(120); op(n); kochLine(order-1,len/3); turn(-60); } kochLine(order-1,len/3); Order } public void op(int n) { } if (n>1) { n = 3*n+1; ned(n); } 0 } • It is unknown whether the call ned(m) terminates for all m ! Order n−1 Order n−1 n>=1 Order n−1 Order n−1

  3. Using Mutual Recursion Syntax diagram for expression • Problem: – compute the value of arithmetic expressions such as 3 + 4 * 5 (3 + 4) * 5 1 – (2 – (3 – (4 – 5))) • Precedence rules: – * and / take precedence over + and – – may overrule using parentheses ( ... ) number Syntax tree for two expressions Mutually recursive methods • Implement 3 methods that call each other recursively getExpressionValue getTermValue getFactorValue • An ExpressionTokenizer is used to group input in tokens. A token being a string of digits or one of "+", "-", "*", "/", "(", ")". Methods: peekToken nextToken public class Evaluator { public int getExpressionValue () { int value = getTermValue (); public Evaluator(String anExpression) { boolean done = false; tokenizer = new ExpressionTokenizer(anExpression); while (!done) { } String next = tokenizer.peekToken(); if ("+".equals(next) || "-".equals(next)) { public int getExpressionValue() { ... } tokenizer.nextToken(); int value2 = getTermValue (); public int getTermValue() { ... } if ("+".equals(next)) value = value + value2; else value = value - value2; public int getFactorValue() { ... } } else done = true; } return value; private ExpressionTokenizer tokenizer; } }

  4. public int getTermValue () { public int getFactorValue () { int value = getFactorValue (); int value; boolean done = false; String next = tokenizer.peekToken(); while (!done) { if ("(".equals(next)) { String next = tokenizer.peekToken(); if ("*".equals(next) || "/".equals(next)) { tokenizer.nextToken(); tokenizer.nextToken(); value = getExpressionValue (); int value2 = getFactorValue (); next = tokenizer.nextToken(); //read ")" if ("*".equals(next)) value = value * value2; } else value = else value = value / value2; Integer.parseInt(tokenizer.nextToken()); } else done = true; } return value; return value; } } Random trees and flowers Random trees and flowers Recursive trees Variation by randomization Order n−1 BRANCH_ANGLE 3 smaller trees/branches Order n−1 Order n−1 = leaf trunk Tree trunk Order 0 n>=1 • leaf, branch, trunk differ by colors and thickness • 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 leaf/branch/trunk • Subtrees are tilted with angle to neighbor being BRANCH_ANGLE=13 deg. Order 0 1 2 3 4 5 6

  5. Extending CCrayon class TreeCrayon import java.awt.*; • CCrayon is a variant of Crayon with 2 extra public class TreeCrayon extends CCrayon { methods: setColor , setWidth /** tree draws a random tree * @param order - order of tree • class TreeCrayon will inherit all the CCrayon * @param len - length of trunk */ methods, and get one new public method: public void tree(int order, int len) {...} public void tree(int order, int len) {...} /** leaf draws maybe(!) a leaf of a random color • Application: * @param len - side length of leaf */ TreeCrayon c = new TreeCrayon(); private void leaf(int len) { ... } c.jumpto(200,400); private final static int BRANCH_MAX = 6; c.turn(-90); private final static int BRANCH_ANGLE = 13; c.tree(6,40); private final static double BRANCH_PROB = 0.4; private final static double LEAF_PROB = 0.3; } Recursive method tree Method leaf public void tree (int order, int len) { private void leaf(int len) { if (order==0) leaf (len/2); if (Math.random()<LEAF_PROB) { else { if (Math.random()<0.5) setColor(Color.red); int bias = (int) (2*Math.random()); if (order+bias >=6) setColor(Color.black); else setColor(Color.yellow); else if (order+bias >=4) setColor(Color.gray); setWidth(2); else setColor(Color.green); turn(-BRANCH_ANGLE/2.0); move(len); setWidth(2*order); move(len); turn(BRANCH_ANGLE); move(len); turn((BRANCH_ANGLE*(BRANCH_MAX-1))/2.0); turn(180-BRANCH_ANGLE); move(len); for (int i = 1 ; i<=BRANCH_MAX ; i = i+1 ) { turn(BRANCH_ANGLE); move(len); if (Math.random()<BRANCH_PROB) tree (order-1, len-2); turn(180-BRANCH_ANGLE/2.0); turn(-BRANCH_ANGLE); } } } turn((BRANCH_ANGLE*(BRANCH_MAX+1))/2.0); turn(180); jump(len); turn(-180); //return pen to base of tree } } Recursion in general: Termination Thinking recursively vs efficiency • Recursive solution may be natural and simple to program • Recursive call need not terminate public long fib(int n) { public void loopingRecursiveMethod() { if (n <= 1) return 1; loopingRecursiveMethod(); else return fib(n - 1) + fib(n - 2); } } • Any reasonable recursive method should have recursion • But iterative solution may be more efficient public long iterativeFib(int n) { condition if (n <= 1) return 1; long fold = 1; public long fib(int n) { long fold2 = 1; no recursive call if (n <= 1) return 1; long fnew = 1; else return fib(n - 1) + fib(n - 2); for (int i = 2; i <= n; i++) { } fnew = fold + fold2; recursive call fold2 = fold; private void kochLine(int order, double len) { fold = fnew; if (order == 0) no recursive call } else if (order > 0) recursive call return fnew; } }

Recommend


More recommend