1.05k likes | 1.07k Views
Learn about recursion in programming with circular definitions, examples of recursive methods, and how recursion works with turtle graphics in Java. Explore bent line drawing functions and fix recursive method errors.
E N D
Chapter 11: Recursion Introduction to Recursion and Graphics More About Recursion Compiler Construction
Recursion • Circular definitions Programming and Problem Solving With Java
Recursion • Sometimes, a circular definition makes sense • Example: teaching a robot to climb stairs • To climb a set of stairs: • 1. If you're at the top of the stairs, stop this process. • 2. Put one foot on the next step, and push off with the other foot. • 3. Follow the process, To climb a set of stairs. • Circular: definition used in itself • Why this works • Stopping rule • Robot gets closer each time through Programming and Problem Solving With Java
Recursion • Recursion • Circular definition in programming • Recursion makes a group of statements repeat • Recursive method: defined using itself • Method repeats until stopping rule is true • Iterative method • Uses looping statements (for, while, do-while) to make statements repeat Programming and Problem Solving With Java
Recursion and Graphics • Recursion works well with turtle graphics • Example: Draw a bent line • Iin SmartTurtle: • // drawBentLine: Draws a line with a "bend" in it. Size is • // the length of the line from start point to • // end point, ignoring the bend • void drawBentLine(int size) • throws TurtleException • { • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • this.turnRight(120); • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • } • In main(): • myTurtle.drawBentLine(1000); Programming and Problem Solving With Java
Recursion and Graphics • Fancier bent line - each line segment a bent line • // drawAnotherBentLine: Draws a line with a "bend" in it. • // Size is the length of the line • // from start point to end point, • // ignoring the bend • // ignoring the bend • void drawAnotherBentLine(int size) • throws TurtleException • { • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • this.turnRight(120); • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • } • // drawBentLine: Draws a line with a "bend" in it. Size is • // the length of the line from start point to • // end point, ignoring the bend • void drawBentLine(int size) • throws TurtleException • { • this.drawAnotherBentLine(size / 3); • this.turnLeft(60); • this.drawAnotherBentLine(size / 3); • this.turnRight(120); • this.drawAnotherBentLine(size / 3); • this.turnLeft(60); • this.drawAnotherBentLine(size / 3); • } Programming and Problem Solving With Java
Recursion and Graphics • Even fancier bent line • // drawLastBentLine: Draws a line with a "bend" in it. • // Size is the length of the line • // from start point to end point, • // ignoring the bend • void drawLastBentLine(int size) • throws TurtleException • { • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • this.turnRight(120); • this.move(size / 3); • this.turnLeft(60); • this.move(size / 3); • } • // drawAnotherBentLine: Draws a line with a "bend" in it. • // Size is the length of the line • // from start point to end point, • // ignoring the bend • void drawAnotherBentLine(int size) • throws TurtleException • { • this.drawLastBentLine(size / 3); • this.turnLeft(60); • this.drawLastBentLine(size / 3); • this.turnRight(120); • this.drawLastBentLine(size / 3); • this.turnLeft(60); • this.drawLastBentLine(size / 3); • } Programming and Problem Solving With Java
Recursion and Graphics • How far can this process go? • drawBentLine() calls • drawAnotherBentLine(), which calls • drawLastBentLine() • Can drawLastBentLine() call drawReallyLastBentLine()??? • (Will we run out of meaningful method names?) Programming and Problem Solving With Java
Original drawBentLine() void drawBentLine(int size) throws TurtleException { this.move(size / 3); this.turnLeft(60); this.move(size / 3); this.turnRight(120); this.move(size / 3); this.turnLeft(60); this.move(size / 3); } Looks like the others void drawAnotherBentLine(int size) throws TurtleException { this.drawLastBentLine(size / 3); this.turnLeft(60); this.drawLastBentLine(size / 3); this.turnRight(120); this.drawLastBentLine(size / 3); this.turnLeft(60); this.drawLastBentLine(size / 3); } move() drawBentLine() void drawBentLine(int size) throws TurtleException { this.drawBentLine(size / 3); this.turnLeft(60); this.drawBentLine(size / 3); this.turnRight(120); this.drawBentLine(size / 3); this.turnLeft(60); this.drawBentLine(size / 3); } Won't work No move() instructions Doesn't stop Recursion and Graphics Programming and Problem Solving With Java
Recursion and Graphics • To fix drawBentLine() so it calls itself correctly • Make it move • Make it stop • // drawBentLine: Draws a line with a "bend" in it. Size is • // the length of the line from start point to • // end point, ignoring the bend • void drawBentLine(int size, int count) • throws TurtleException • { • if (count == 0) • { • this.move(size); • } • else • { • this.drawBentLine(size / 3, count - 1); • this.turnLeft(60); • this.drawBentLine(size / 3, count - 1); • this.turnRight(120); • this.drawBentLine(size / 3, count - 1); • this.turnLeft(60); • this.drawBentLine(size / 3, count - 1); • } • } Programming and Problem Solving With Java
Recursion and Graphics drawBentLine(1000, 3) drawBentLine(1000, 4) drawBentLine(1000, 5) Programming and Problem Solving With Java
Recursion and Graphics • Fancy hexagons • Tricky to do withoutrecursion • Recursion makesit simple Programming and Problem Solving With Java
Recursion and Graphics • How to construct a fancy hexagon Programming and Problem Solving With Java
Recursion and Graphics • Start with drawHexagon() • // drawHexagon: Draws a hexagon of the given size • void drawHexagon(int sideLength) • throws TurtleException • { • for(int sideNum = 0; sideNum < 6; sideNum++) • { • this.move(sideLength); • this.turnRight(60); • } • } • Add hexagon to each vertex - without recursion • // drawFancyHexagon: Draws a hexagon of the given size, with • // a smaller hexagon at each vertex • void drawFancyHexagon(int sideLength) • throws TurtleException • { • for(int sideNum = 0; sideNum < 6; sideNum++) • { • this.move(sideLength); • this.turnLeft(120); • this.drawHexagon(sideLength / 2); • this.turnRight(180); • } • } Programming and Problem Solving With Java
Recursion and Graphics • Recursive version of drawFancyHexagon() • // drawFancyHexagon: Draws a hexagon of the given size, with • // a smaller hexagon at each vertex • void drawFancyHexagon(int sideLength, int depth) • throws TurtleException • { • if (depth > 0) • { • for(int sideNum = 0; sideNum < 6; sideNum++) • { • this.move(sideLength); • this.turnLeft(120); • this.drawFancyHexagon(sideLength / 2, depth - 1); • this.turnRight(180); • } • } • } Programming and Problem Solving With Java
Recursion and Graphics • How drawFancyHexagon(200, 3) works Programming and Problem Solving With Java
More About Recursion • Can use recursion for many other applications besides graphics • Often simpler and shorter than iteration • Example: recursive power() method • Returns floating-point number raised to integer power • Like Math.pow() (but exponent in power() is int) • Example • double x = power(10.0, 2); Programming and Problem Solving With Java
100.0 10.0 power(10.0, 1) = 10.0 power(10.0, 0) power(10.0, 0) = 1.0 More About Recursion: power() • Definition of power(number, exponent) • If exponent is 0, then result is 1.0 • If exponent is greater than 0, then result is number times power(number, exponent - 1) • Example: power(10.0, 2) power(10.0, 2) = 10.0 power(10.0, 1) Programming and Problem Solving With Java
More About Recursion: power() • Definition of power(number, exponent) • If exponent is 0, then result is 1.0 • If exponent is greater than 0, then result is number times power(number, exponent - 1) • In Java • // power: Raises number to the integer power exponent. • // Note: The exponent must be nonnegative. • static double power(double number, int exponent) • { • if (exponent == 0) • { • return 1.0; • } • else • { • return number * power(number, exponent - 1); • } • } Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • 10.0 and 2 are sent to power() Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • Computerevaluatespower(10.0, 1) Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • Computerevaluatespower(10.0, 0) Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • 1.0 returned toexpression infirst copy Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • 10.0 returned toexpression inoriginal method Programming and Problem Solving With Java
More About Recursion: power() • How the computer executes power(10.0, 2) • 100.0 returned to assignment Programming and Problem Solving With Java
More About Recursion: factorial() • Factorial of integer k = 1 2 3 ... k • Written k! • Example • 3! = 3 2 1 = 6 • Definition of factorial(n) • if n is 0, then factorial(n) is 1 • if n greater than 0, factorial(n) is n factorial(n - 1) • Example • 2! = 2 1 = 2 • 3! = 3 2! = 6 Programming and Problem Solving With Java
2 1 factorial(1) = 1 factorial(0) factorial(0) = 1 More About Recursion: factorial() • Definition of factorial(n) • if n is 0, then factorial(n) is 1 • if n greater than 0, factorial(n) is n factorial(n - 1) • Example: factorial(2) factorial(2) = 2 factorial(1) Programming and Problem Solving With Java
More About Recursion: factorial() • Factorial in Java (recursive version) • // factorial: Returns the factorial of the number. • // Note: The number must be positive. • static int factorial(int number) • { • if (number == 0) • { • return 1; • } • else • { • return number * factorial(number - 1); • } • } • Iterative solution is faster and takes less memory • // factorial: Returns the factorial of the number. • // Note: The number must be positive. • static int iFactorial(int number) • { • int product = 1; • for (int i = 1; i <= number; i++) • { • product = product * i; • } • return product; • } Programming and Problem Solving With Java
More About Recursion: towers() • Towers of Hanoi Puzzle • Object: Move all disks to right peg • Can only move one disk at a time • Can't put a larger disk over smaller one Programming and Problem Solving With Java
More About Recursion: towers() • Solution for 1 disk Programming and Problem Solving With Java
More About Recursion: towers() • Solution for 2 disks Programming and Problem Solving With Java
More About Recursion: towers() • Solution for 3 disks Programming and Problem Solving With Java
More About Recursion: towers() • Simple solution to 3 disk problem • Move two smaller disks from left to center • Move large disk from left to right • Move two smaller disks from center to right • BUT... YOU CAN'T MOVE TWO DISKS!! • But we can use the 2 disk solution to move two disks • Look at it this way... • Use 2 disk solution to move two smaller disks from left to center • Move large disk from left to right • Use 2 disk solution to move two smaller disks from center to right Programming and Problem Solving With Java
More About Recursion: towers() • Solution in Java • Each n-disk problem uses n-1 disk problem • // solveTower: Displays solution to the Tower of Hanoi • // problem for the given number of disks • static void solveTower(int numDisks, • String sourcePeg, • String workPeg, • String destPeg) • { • if (numDisks == 1) • { • System.out.println("Move disk from " + sourcePeg • + " peg to " + destPeg + " peg."); • } • else • { • solveTower(numDisks - 1, sourcePeg, destPeg, workPeg); • solveTower(1, sourcePeg, workPeg, destPeg); • solveTower(numDisks - 1, workPeg, sourcePeg, destPeg); • } • } • Recursion!! Programming and Problem Solving With Java
How Recursion Works • When method calls itself, almost like it makes another copy of itself • Don't need to copyexecutablestatements • Only need copiesof local variablesand parameters Programming and Problem Solving With Java
Recursion uses a run-time stack Stack: last-in, first-out data structure Push operation: puts value into the stack Pop operation: gets value out of the stack How Recursion Works Programming and Problem Solving With Java
How Recursion Works • When program calls a method • Computer saves return point in activation record • When method finishes • Computer gets return point from activation record • Activation records saved on run-time stack • Each activation record contains • Return point • Local variables for the method • Parameters for the method Programming and Problem Solving With Java
How Recursion Works • Example: power(10.0, 2) Programming and Problem Solving With Java
How Recursion Works Programming and Problem Solving With Java
How Recursion Works Programming and Problem Solving With Java
How Recursion Works Programming and Problem Solving With Java
How Recursion Works Programming and Problem Solving With Java
How Recursion Works Programming and Problem Solving With Java
Infinite Recursive Loops • Recursion without a stopping rule • // Does this go into an endless recursive loop? • static void endlessLoop() • { • endlessLoop(); • } • Does this go on forever? • Activation records eventually fill the run-time stack • Run with Sun Java 1.1.7 • $ java RecursionEndless • A nonfatal internal JIT (3.00.072b(x)) error 'Structured Exception(c00000fd)' ha • s occurred in : • 'RecursionEndless.endlessLoop ()V': Interpreting method. • Please report this error in detail to http://java.sun.com/cgi-bin/bugreport.cg • i • java.lang.StackOverflowError • at RecursionEndless.endlessLoop(RecursionEndless.java) • Some compilers recognize this as tail recursion Programming and Problem Solving With Java
Recursion and Iteration • Recursive version of power() • // rPower: Raises number to the integer power exponent. • // Note: The exponent must be nonnegative. • // Recursive version. • static double rPower(double number, int exponent) • { • if (exponent == 0) • { • return 1.0; • } • else • { • return number * power(number, exponent - 1); • } • } • Iterative version of power() • // iPower: Raises number to the integer power exponent. • // Note: The exponent must be nonnegative. • // Iterative version. • static double iPower(double number, int exponent) • { • double temp = 1.0; • for (int i = 1; i <= exponent; i++) • { • temp = temp * number; • } • return temp; • } Programming and Problem Solving With Java
Recursion and Iteration • Running time of recursion about 2X iteration • Extra time needed for run-time stack manipulation • Stack overflow with recursive version Programming and Problem Solving With Java
Recursion and Iteration • Use recursion when you know the number of successive recursive calls • Each call is activation record on run-time stack • Recursive power method takes O(n) space for the stack • Many recursive methods don’t use much stack space • Binary search takes O(log n) space • Towers of Hanoi takes O(n) space, but n should be < 30 or so • Recursion is appropriate when not much stack space is required • Tail recursion optimization can make O(n) appropriate Programming and Problem Solving With Java
Recursion and Iteration • Is this an appropriate use of recursion? • import Keyboard; • class RecursivePrompt • { • public static void main(String[] args) • throws java.io.IOException • { • char operation = Keyboard.readChar("Add Multiply Quit: ", "amq"); • if (operation != 'q') • { • int num1 = Keyboard.readInt("Enter first number: "); • int num2 = Keyboard.readInt("Enter second number: "); • if (operation == 'a') • { • System.out.println(num1 + num2); • } • else • { • System.out.println(num1 * num2); • } • main(args); • } • } • } Add Multiply Quit: a Enter first number: 1 Enter second number: 2 3 Add Multiply Quit: m Enter first number: 3 Enter second number: 4 12 Add Multiply Quit: q Programming and Problem Solving With Java
Recursive Binary Search • // binarySearch: Returns the location of itemToFind, or -1 • // if not found. The array must be sorted in • // ascending order. • // (Recursive version) • static int binarySearch(double[] array, // array to search • double itemToFind, // item to look for • int bottom, int top) // area to look • { • int middle; • if (bottom > top) • { • return -1; • } • else • { • middle = (bottom + top) / 2; • if (array[middle] > itemToFind) • { • // Element must be in the lower half of the array • return binarySearch(array, itemToFind, bottom, middle - 1); • } • else if (array[middle] < itemToFind) • { • // Element must be in the upper half of the array • return binarySearch(array, itemToFind, middle + 1, top); • } • else • { • // Found the item • return middle; • } • } • } Programming and Problem Solving With Java
Compiler Construction • A compiler translates source code to executable machine code Programming and Problem Solving With Java