Presentation is loading. Please wait.

Presentation is loading. Please wait.

Recursion Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems We will focus on: thinking in.

Similar presentations


Presentation on theme: "Recursion Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems We will focus on: thinking in."— 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 When defining an English word, a recursive definition is often not helpful But in other situations, a recursive definition can be an appropriate way to express a concept Before applying recursion to programming, it is best to practice thinking recursively

3 Recursive Thinking We have used methods that call other methods to help them solve a problem. Sometimes methods need to call themselves again. A recursive definition is one which uses the word or concept being defined in the definition itself.

4 Recursion But in other situations, a recursive definition can be an appropriate way to express a concept. Let’s look at a presentation which illustrates such thinking.

5 Recursive Definitions
Consider the following list of numbers: 24, 88, 40, 37 Such a list can be defined as A LIST is a: number or a: number comma LIST That is, a LIST is defined to be a single number, or a number followed by a comma followed by a LIST The concept of a LIST is used to define itself

6 Recursive Definitions
The recursive part of the LIST definition is used several times, terminating with the non-recursive part: number comma LIST , 88, 40, 37 , 40, 37 , 37 number 37

7 Infinite Recursion All recursive definitions have to have a non-recursive part 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, except that the loop is endlessly calling itself..

8 Recursion The non-recursive part is often called the base case. The algorithm must ensure that the base case is reached. Recursion is based on two key problem-solving concepts: divide and conquer and self-similarity. We repeatedly break down a big problem into a sequence of smaller and smaller problems until we arrive at the trivial case.

9 Recursion Look at the task of printing hello 5 times. It involves printing hello N-1 times. Solving this task involves the similar task of printing hello N-2 times etc.

10 Recursion /* prints each character of s – e.g “hello”
public void printString(String s) { if(s.length() == 1 ) return else{ System.out.print(s.charAt(0)); printString(s.substring(1)); // takes off the first character of the word } Prints out the first charaction of “hello”, then “ello”, then “llo” then “lo” then “o”

11 Recursive Definitions
N!, 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 concept of the factorial is defined in terms of another factorial Eventually, the base case of 1! is reached

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

13 Recursive Programming
When a method calls itself, it is called a recursive method The code of a recursive method must be structured to handle both the base case and the recursive case Each call to the method sets up a new execution environment, with new parameters and local variables As always, when the method ends, execution returns to the method that invoked it (which is an earlier invocation of itself)

14 Recursion The following method solves the summation of the numbers from 1 and any positive integer N. 1. public int sum(int N) { int result; if(N ==1) result = 1; else result = N + Sum (N-1); return result; } This method embodies our recursive definition that the sum of the numbers between 1 and N = N + the sum of the numbers between 1 and N-1.

15 Recursive Programming
main sum sum(3) sum(1) sum(2) result = 1 result = 3 result = 6

16 Recursion If we pass an initial value of 2 to the sum method:
Since N is not equal to 1, the method sum is called again with an argument of N-1 or 1. This is a new call to the method sum, with a new parameter N and a new local variable result. This call and its environment is stored on the stack Since N is now equal to 1, the result of 1 is returned without any further recursive calls. Control returns to the first version of sum. The return value of 1 is added to the initial value of N in that call to sum which is 2. Therefore result is assigned the value 3 which is returned to the main method.

17 Recursion The base case is when N equals 1. At this point no further calls are made to the sum method. The recursion begin to unwinds into the earlier version of the sum method, returning a value each time. Each return value contributes to the summation of the sum at a higher level. Without the base case, infinite recursion would result. Each call also requires more memory space so that infinite recursion results in a run-time error indicating that memory has been exhausted.

18 Recursion The call to sum is recursive because it is calling itself. The parameter to sum is decremented each time sum is called, until it reaches the base case of 1. If the method is called with a value of 1, which is stored in N,, the result 1 is returned to main. MAIN result = 2 MAIN sum(2) sum(1) result = 1 SUM SUM result = 1 SUM

19 Recursive Programming
Note that just because we can use recursion to solve a problem, that does not mean this is the optimal solution. For instance, we usually would not use recursion to solve the sum of 1 to N problem, because the iterative version is easier to understand and requires less memory if N is a large number.

20 Recursion The iterative solution is easier to understand:
sum = 0; for(int number = 1; number <=N; number++) sum += number; Recursion has memory overhead. However, for some problems, recursion provides an elegant solution, often cleaner than an iterative version

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

22 An example if the number has only one digit { write that digit }
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 { write that digit } else { Write the digits of number/10 vertically write the single digit of number % 10

23 The WriteVertical method
public static void writeVertical(int number) { if (number < 10) System.out.println(number); // Write the one digit. else { writeVertical(number/10); // Write all but the last digit. System.out.println(number % 10); // Write the last digit. }

24 writeVertical The base case here is simple - when number has only 1 digit. The recursive call occurs where: writeVertical(number/10); // Write all but the last digit System.out.println(number % 10); // Write the last digit. What actually happens with writeVertical(3) The argument 3 is copied the method’s parameter - number which provides it with an initial value.

25 writeVertical Since the number is less than 10, it writes the number.
With an argument greater than 10 like 37, it would go to the statements in the else part of the code. else { writeVertical(number/10); // Write all but the last digit. System.out.println(number % 10); // Write the last digit. } Since 37/10 is 3 this is an activation of the previous problem of writeVertical(3) which prints out 3 on a single line. After the 3 is printed, we go to the next line which prints out the last digit which is 7 % 10.

26 Recursion When a method - e.g. method 1 -is activated, the computer stores information about the method before activating it. It stores method 1’s parameters and local variables and information that will allow it to return to place in the code where the method call occurs. Then it starts the actual method. This is called the Activation Record of a Stack Frame.

27 Recursion If another method - 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 where the call for the second method occurred in the first method. It will continue to this for every recursive method call.

28 Recursion An Activation Record is kept for all methods.
Activation Record for WriteVertical number: 36 When the method returns, the computation should begin at line where execution stopped

29 Executing superWriteVertical
Using the number 36 it enters the method. The number is not less than 10 so it makes a recursive call to WriteVertical which has its own Activation Record. The Activation Records are stored in a stack called the Execution Stack Activation Record First call number: 36 When the method returns, the computation should begin at SPOT 1 of the program.

30 TRACING EXECUTION Activation Record for first call to WriteVertical
number: 36 When the method returns, the computation should begin at SPOT 1 of the program. Activation Record for second call to WriteVertical number: 3 Method finishes and returns

31 Tracing Execution WriteVertical(36) which makes a call to
Eventually in all recursive functions there must be a stopping case or else there is an infinite sequence of recursive calls

32 Using Recursion Recursion is best served when it is easy to define a smaller subset of the problem in terms of the original. 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. In Repeating_Pictures.java, the applet displays several pictures.. There are actually only 3 distinct pictures among all the ones shown.

33 Using Recursion Recursion is best served when it is easy to define a smaller subset of the problem in terms of the original. 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 (page 483)

34 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. The bottom-left quadrant contain a picture of Mt. Everest. In the bottom-right quadrant is a picture of a mountain goat.

35 Tiled Pictures

36 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). It has the same effect as when you look at a mirror in the reflection of another mirror. This repetition continues for several levels.

37 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.

38 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); }

39 // // Performs the initial call to the drawPictures method. // public void paint (Graphics page) { drawPictures (APPLET_WIDTH, page); } }

40 // // Draws the three images, then calls itself recursively. // public void drawPictures (int size, Graphics page) { 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) drawPictures (size/2, page); }

41 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. 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 Draw_ pictures applet relative to the co-ordinates <0,0>

42 Drawing Mirrors The two lines defining the four quadrants are drawn relative to the size of the current draw area. 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.

43 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 (page 472) See Maze.java (page 474)

44 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. The base case is an invalid move or one which reaches the final destination. 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 to indicate attempted and successful paths through the maze.

45 // 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} };

46 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. The Maze_Search class contain the main method which instantiates the maze and prints out it as a matrix, solves the maze if possible and prints out solved version of the maze. 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.

47 Recursion A move is considered valid if: 1. It stays within the grid
2. if the grid contains a ‘1’ in that cell The initial call to traverse passes 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 //======================================
// 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

50 The 3 possibilities for the base case for each recursive call are:
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!

51 // Recursively traverse the maze
// Recursively traverse the maze. and inserts special characters indicating locations that have been tried and that eventually become part of the solution. public boolean traverse (int row, int column) {   oolean 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 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

52 Mazes If the current location is not the bottom-right corner , we search for a solution in each of the primary directions, if necessary. Down, Right Up and Left First, we look down by recursively calling the traverse method and passing in the new location The logic of the solve methods starts all over again using this new position.

53 Mazes A solution is found by either starting down from the current location or it is not found. If it’s not found, we try moving right, then up. Finally if no direction yields a correct path we try left. If no direction from this location yields a correct solution, then there is not path from this location and the traverse method returns false.

54 Maze_Search If a solution was found from the current location, the grid entry is changed to a 7. These are marked when the method calls unwind. Therefore, when the final maze is printed: The locations left on the stack are part of the solution. the zeros still indicate a blocked path and A 1 indicates an open path that was never tried A 3 indicates a path that was tried but failed to yield a correct solution 4. A 7 indicates a part of the final solution of the maze

55 Maze_Search Maze_Search Solution moves are down right up and left


Download ppt "Recursion Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems We will focus on: thinking in."

Similar presentations


Ads by Google