1 / 83

Recursion

Recursion. Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems We will focus on: thinking in a recursive manner programming in a recursive manner the correct use of recursion recursion examples. Recursive Thinking.

bob
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 • Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems • We will focus on: • thinking in a recursive manner • programming in a recursive manner • the correct use of recursion • recursion examples

  2. Recursive Thinking • A recursive definition is one which uses the word or concept being defined in the definition itself, e.g. • “A friend is a person who is a friend “ • When defining an English word, a recursive definitionis not effective. • But in other situations, a recursive definition can be the best way to express a concept

  3. Recursive Thinking • We have used methods that call other methods to help them solve a problem. • Sometimes methodsneed to call themselves again.

  4. A Simple Recursive Method • // This method does not stop - it is in an infinite loop • public static void forgetMeNot() • { • System.out.println(“I Miss You”); • forgetMeNot();// a recursive call to itself again • } The method prints “I Miss You” and then calls itself infinitely: • I Miss You • I Miss You • I Miss You • …( forever!)

  5. Writing a recursive method • Problem Statement: • The previous method does not stop executing so there is an endless loop: • Problem: Write a recursive method that: • prints “I Miss You” n times and • signs off “Love , Me”. • It will run n times

  6. public class GreetingCard • { • // main method calls forgetMeNot with parameter “3” • public static void main(String[] args) • { • forgetMeNot(3); // invokes method for the first time • System.out.println(“Love, Me”); (SPOT 1) • } • //*************************************************** • public static void forgetMeNot(int n) • //nis the number of times the message is printed. • { • if (n != 0) // base case which stop recursive calls • { • System.out.println(“I Miss You”); • forgetMeNot(n – 1 ); // the recursive call • (SPOT 2) // There could be more code here • } • }

  7. Writing Recursive methods • Output • I Miss You • I Miss You • I Miss You • Love, Me • The recursive method forgetMeNot(...) • is called by main(...) and passed the argument “3”.

  8. Main method begins with the call forgetMeNot(3): What the method does: • prints “I Miss you” • Calls forgetMeNot(2): • prints “I Miss You” • Calls forgetMeNot(1): • prints “I Miss You” • Calls forgetMeNot(0): **** next does nothing because the condition (n!=0) evaluates to false -it is 0 forgetMeNot(0) then returns to the previous call of: forgetMeNot(1), picks up at location where it left (SPOT 2) forgetMeNot(1) has no more code after recursive call in (SPOT 2) Program control returns to the suspended forgetMeNot(2) - no more code at (SPOT 2) control returns to forgetMeNot(3): Last method done so passes control back to main Main: prints “Love, Me” at (SPOT 1)

  9. Visualization of method calls 1. main 2. forgetMeNot(3) 3. “I Miss You” 4. forgetMeNot(2) 5. “I Miss You” 6. forgetMeNot(1) 7. “I Miss You” 8. forgetMeNot(0) -- base case 9. return 10. Return to (1) // to where it left the method 11. Return to (2) 12. Return to (3) 13. “Love, Me” The trace is read from top to bottom as the program executes: Indentations are made every time a recursive call is made. When a method returns to where it left the calling method (AT SPOT 2) the indentation goes back to the previous level. Execution continues at the statement following the recursive call. (SPOT 1)

  10. Recursive Programming • Just because we can use recursion to solve a problem, • that does not mean this is the optimal solution. • The iterative version is easier to understand and requires less memory if N is a large number. • For instance why not just print out forgetMeNot three times in a loop??????

  11. Infinite Recursion • All recursive definitions have to have a non-recursive part - a stopping case or base case • If they didn't, there would be no way to terminate the recursive path • Such a definition would cause infinite recursion • This problem is similar to an infinite loop

  12. Recursion • The non-recursive part is often called the base case. • e.gif (n != 0) // base case which stop recursive calls • The algorithm must ensure that the base case is reached.

  13. Solving a Recursive Problem Recursion is based on a key problem- • divide and conquer and self-similarity. • Repeatedly breaking down a big problem into a sequence of smaller and smaller problems • until we arrive at the base case.

  14. Recursion • Look at the task of printing the characters of “hello” • It involves printing the first character and then the method calls itself with the first character removed. • Solving this task involves the similar task of printing hello minus the first character (look up subString method in the String class

  15. Recursion /* prints each character of S ( str = “hello”) • public void printString(String str) • { • if( str.length() == 0 ) // base case • return // leave the method • else • { • System.out.print( str.charAt(0) ); //print first char • printString(str.substring(1));// REMOVES ONE CHAR • } // end of method str.substring(1)returns the string starting at “e” For each subsequent call it removes the first character

  16. HELLO – PRINTING CHARACTERS • FOR INPUT OF ‘HELLO’ OUTPUT: value stored -str = “HELLO” • H hello • E ello • L llo • L lo • 0 O

  17. Recursive Definitions • For any positive integer, • N is defined to be the product of all integers between 1 and N inclusive • This definition can be expressed recursively as: 1! = 1 N! = N * (N-1)! • The factorial is defined in terms of another factorial • Eventually, the base case of 1! is reached

  18. Recursive Definitions 120 24 6 2 5! 5! 5 * 4! 4 * 3! 3 * 2! 2 * 1! 1 1 = BASE CASE

  19. How recursion works • The code of a recursive method must be structured to handle both the: • base case which will end the recursive calls and • the recursive case

  20. Example • To write a method that stacks non-negative numbers to the screen vertically such as 1 2 3 4 : 1 2 3 4 • We might break the problem into two parts: • Print all the digits but the last one stacked vertically 2. Print the last one.

  21. An example • To print the actual number we would • divide the number by 10 to get the first three digits and • use the mod operator to get the last digit. The pseudocode is: if the number has only one digit // base case { write that digit to output } else { Write the digits of number/10 vertically write the single digit of number % 10 - last digit }

  22. The WriteVertical method • public static void writeVertical(int number) { • if (number < 10) // base case • System.out.println(number); // prints number under 10. • else • { • // divides number by 10 and calls itself again • writeVertical(number/10); // call itself again (no /10). • // prints the last digit WHEN RECURSION UNWINDS • System.out.println(number % 10); • } • }

  23. writeVertical • The base caseis : when the number has only 1 digit. And then that digit is printed. e.g. number = 4 (4 % 10 = 4 ) • The recursive call occurs where: • // writeVertical calls itself until it reaches the base case – number < 10 // base case • // digits are printed in unwinding phase • System.out.println(number % 10);

  24. public static void writeVertical(int number) { • public static void writeVertical(int number) { • if (number < 10) // base case • System.out.println(number); // prints numbers under 10. • else { 5.writeVertical(number/10); // call itself until base case // Spot 1 – location to return to when recursion unwinds 6. System.out.println( number % 10 ); } }

  25. TRACING EXECUTION TRACING EXECUTION • ( Activation Record - second call to superWriteVertical number: 3 Prints out the number 3 (number is less than 10) When the method returns, the computation should begin at SPOT 1 of the program. Activation Record for first call to superWriteVertical number: 36 When the method returns, the computation should begin at line SPOT1(line 5) of the program. Activation Record – returns to previous call to superWriteVertical when number is 36 The computation should begin at SPOT 1 of the programwhere it prints the 6

  26. How the Activation calls work • When the recursive call to superWritevertical (36) make a call to tosuperWritevertical( 3) • The number “3” is printed out. • The Activation Record for the call is popped from the stack and • Activation Record tells the computer where to re-start execution – • at SPOT 1.

  27. Tracing Execution The record is: • superWriteVertical(36) makes a recursive call to: • superWriteVertical(3) which prints out the “3” • There is no more code so execution returns to spot1 // The last line after Spot1 writes out digit 6 System.out.println( 36 % 10 );

  28. Recursion • If another method - called method 2- is called from within method 1, • method 1’s execution is temporarily stopped and the same information is stored for method 2. • It stores the location of the call for the second method . • It will continue to this for every recursive method call. • This information is stored in Activation Records

  29. Using Recursion • Consider the task of repeatedly displaying a set of images in a mosaic that is reminiscent of looking in two mirrors reflecting each other. • The base case is reached when the area for the images shrinks to a certain size. • See MirroredPictures.java

  30. Recursion • The entire area is divided into 4 quadrants, separated by lines. • A picture of the world(with a circle indicating the Himalayan mountain section) is in the top-right quadrant. • a picture of Mt. Everest - The bottom-left quadrant contain • a picture of a mountain goat- in the bottom-right quadrant

  31. Tiled Pictures

  32. Repeating Pictures • In the top left quadrant contains a copy of the entire collage, including itself. • In this smaller version you can see the three simple pictures in their three quadrants. • And again, in the upper-left corner the picture is repeated (including itself). • .

  33. Mirrored_Images • This effect is created easily using recursion. • In the applet, the paint method invokes another method called draw pictures(). • The draw_pictures() method accepts a parameter that defines the size of the area in which pictures are displayed. • It draws the three standard images using drawImage(). • The draw_pictures method draws the upper left quadrant recursively.

  34. public class TiledPictures extends JApplet{ private final int APPLET_WIDTH = 320; private final int APPLET_HEIGHT = 320; private final int MIN = 20; // smallest picture size private Image world, everest, goat;//----------------------------------------------------------------- // Loads the images. //----------------------------------------------------------------- public void init() { world = getImage (getDocumentBase(), "world.gif");everest = getImage (getDocumentBase(), "everest.gif"); goat = getImage (getDocumentBase(), "goat.gif");setSize (APPLET_WIDTH, APPLET_HEIGHT); }

  35. //----------------------------------------------------------------- //Performs the initial call to the drawPictures method. //----------------------------------------------------------------- public void paint (Graphics page) {drawPictures (APPLET_WIDTH, page); }} // Starts with the full size of the applet which will // be divided for every subsequent call

  36. //-----------------------------------------------------------------// Draws the three images, then calls itself recursively. // reducing the size of the images with each call. //-----------------------------------------------------------------public void drawPictures (int size, Graphics page) { page.drawLine (size/2, 0, size/2, size); // verticalpage.drawLine (0, size/2, size, size/2); // horizontal page.drawImage (everest, 0, size/2, size/2, size/2, this);page.drawImage (goat, size/2, 0, size/2, size/2, this); page.drawImage (world, size/2, size/2, size/2, size/2, this); if (size > MIN) // if there is room to draw, call againdrawPictures (size/2, page); }

  37. Mirrored_Images • On each invocation, • if the drawing area is large enough • the draw_pictures method is invoked again, using a smaller drawing area. • Eventually the drawing area becomes so small that the recursive call is not performed.

  38. Halving the size of the picture • Each time the draw-pictures method is invoked, • the size passed as a parameter is used to determine the area in which the pictures are presented • relative to the co-ordinates <0,0>

  39. Drawing Mirrors • The drawImage method automatically scales the pictures to fit in the area indicated. • The base case of the recursion in this problem specifies a minimum size for the drawing area. • Because the size is decreased each time, • eventually the base case is reached and the recursion stops. • That is why the last upper left corner is empty in the smallest version of the collage.

  40. Maze Traversal We can use recursion to find a path through a maze • From each location, we can search in each direction • Recursion keeps track of the path through the maze • The base case is an invalid move or reaching the final destination • See MazeSearch.java • See Maze.java

  41. Using Recursion • A maze is solved by trial and error – • choosing a direction, • following a path, • returning to a previous point if the wrong move is made. • As such, it is another good candidate for a recursive solution.

  42. In Maze_Search.java, • a 2-D array of integers filled with 0’s and 1’s. • A ‘1’ indicates a clear path and a ‘0’ a blocked path. • As the maze is solved these parameters are changed • to other values (3,1) to • indicate attempted and successful paths through the maze.

  43. // Class Maze represents a maze of characters. The goal is to get // from the top left corner to the bottom right, following a path // of 1's. class Maze { int[][] grid = {{1,1,1,0,1,1,0,0,0,1,1,1,1}, {1,0,1,1,1,0,1,1,1,1,0,0,1}, {0,0,0,0,1,0,1,0,1,0,1,0,0}, {1,1,1,0,1,1,1,0,1,0,1,1,1}, {1,0,1,0,0,0,0,1,1,1,0,0,1}, {1,0,1,1,1,1,1,1,0,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,1,1,1,1,1,1,1,1,1,1} };

  44. Recursion - Maze • The only valid moves are right, left, up and down with no diagonal moves allowed. • The goal is to start in the upper-left corner of the maze (0,0) and find a path that reaches the • bottom-right corner.

  45. Maze_Search class • The Maze_Search class contain the main method which instantiates the maze and prints out it as a matrix. • It solves the maze if possible and • prints out the solved version of the maze.

  46. Traverse – determines valid moves • The recursive method traverse ()returns a boolean value that indicates whether a solution was found. • First the method determines if a move to that row and column is valid. • A move is considered valid if: 1. It stays within the grid 2. if the grid contains a ‘1’ in that cell

  47. Recursion • The initial call to traversepasses in the upper-left location(0,0). • If the move is valid, • the grid entry is changed from a 1 to a 3 • marking this location as visited so that later we don’t retrace out steps.

  48. //====================================== // Determines if a specific location is valid. //=========================================== private boolean valid (int row, int column) { boolean result = false; // check if cell is in the bounds of the matrix if (row >= 0 && row < grid.length && column >= 0 && column < grid[0].length) // check if cell is not blocked and not previously tried if (grid[row][column] == 1) result = true; return result; } // method valid

  49. Then the traverse method determines if the maze has been completed -- • by having reached the bottom right location of the maze. • The 3 possibilities for the base case for each recursive call are: 1. an invalid move because it is out of bounds 2. an invalid move because it has been tried before (it contains a 3) so we go back to a previous cell 3. a move that arrives at the final location – Success!

  50. // Recursively traverse the maze. and inserts special characters indicating locations that have beentried and that eventually become part of the solution. public boolean traverse (int row, int column) { boolean done = false; if (valid (row, column)) // calls method to determine the cell holds a 1 { grid[row][column] = 3; // marks cell as tried and sets it to 3   if (row == grid.length-1 && column == grid[0].length-1) done = true; // maze is solved ,we have reached the end else { done = traverse (row+1, column); // move down as far as possible if (!done) // if that did not work, done = traverse (row, column+1); // move right if (!done) // if that did not work, done = traverse (row-1, column); // move up if (!done) // if that did not work, done = traverse (row, column-1); // move left } if (done) // part of the final path - this is marked when the calls unwind grid[row][column] = 7; // this marks the path to the final solution } // closes if valid return done; } // method traverse

More Related