200 likes | 215 Views
Learn the concept of recursion in programming, its applications, and how to write recursive methods. Explore the Lost Beeper Mine problem as an example.
E N D
Recursion • Recursion • means to recur or to repeat • A different way to get a robot to repeat an action • A programming language that allows recursive definitions (and not all do) • within a new method we can send a simpler form of the same message • using the same method name • Recursion is just another control structure, another programming tool to add to your collection
The Lost Beeper Mine problem • There is corner somewhere in the robot world that has a large number of beepers. The only clue to the location of this treasure is that somewhere, directly ahead of the robot, is a beeper. (There is no intervening wall segments.) The Lost Mine is directly north of the beeper, a distance equal to the number of moves the robot makes to get from its current position to the beeper. • Download Prospector.zipdemo.
How does this work? • Finding the beeper? void findBeeper() { if (! nextToABeeper() ) // robot not next to beeper { move(); // go to next corner findBeeper(); // is the beeper here? } } • In order to find the beeper, we define the method findBeeper() that calls itself to help finish the search • This is a recursive definition
Recursive Definitions • We do not define a method in terms of precisely itself • We define a thing in terms of a simpler, or smaller version of itself • Here we define findBeeper() as • either “nothing” (if the robot is on the corner with a beeper) • or “move(); findBeeper() ” • It is also necessary to know that a beeper does lie in the robot’s path, or we fall into infinite recursion • Every call results in a separate instance of the instruction findBeeper();
Lost Beeper Mine, again • So we have a sense of how we found the position-marker beeper • How did we get to the mine? • At every place we called a simpler version of findMine(), we were leaving some unfinished work behind • A recursive method, as any other method. Must complete its task before control is returned to the call-site of the method (where the method was called from)
findMine() void findMaine() { if (nextToABeeper()) { // found beeper turnLeft() // we know the mine is north of us } else { move();// still looking for beeper findMine();// next method call (call-site) move(); // unfinished business } } • The “unfinished business” must be completed for each recursive call before each method is done. • It is actually this unfinished business that correctly propels us to the lost mine
Process for writing recursive methods • Step 1: Consider the stopping condition (the base case). • What is the simplest case of the problem that can be solved? • (already on the beeper) • Step 2: What does the robot do in the base case? • (turnLeft) • Step 3:Find a way to solve a small piece of the larger problem if not the base case • Reducing the problem in the general case • The general case is that the beeper has not been found • So move and check again • Step 4: Make sure the reduction leads to the base case • The move takes the robot one step closer to the beeper
Iteration vs Recursion • An iterative loop completes each cycle before beginning the next one • A recursive method begins a new instance before completing the current one • The current instance is temporarily suspended • The second instance might be suspended as it calls another • Each successive instance must be completed in turn, last to first • Each recursive method is supposed to make minimal progress toward the base case, it will never be controoled by a loop, but by some form of the IF instruction
Tail Recursion • Tail recursion: Form of recursion in which the recursive call is the last instruction in the method void pickAllBeepers() { if (nextToABeeper()) { pickBeeper(); pickAllBeepers(); // recursive call } }
Tail Recursion and WHILE loops void pickAllBeepers() { if (nextToABeeper()) { pickBeeper(); pickAllBeepers(); // recursive call } } • Execution equivalent with void pickAllBeepers() { while (nextToABeeper()) { pickBeeper(); } }
WHILE loop a special form of recursion • A formal definition of the WHILE loop • We are going to discuss and analyze instructions (the meta-level), not use them • W is the while statement • T is the test • L is the instruction list • The formal definition of W is • W == if (T){L; W;} • Notice that the WHILE statement W is defined in terms of itself
Loop verification • An informal way to reason about loop correctness • Show that instruction works when the initial situation results in the test being false • Show that each time the loop body is executed, the robot’s new situation is a sompler and similar version of the old situation • We need a formal way of thinking about loops to verify that they are correct
Loop Invariants • A key concept • Definition: an assertion which is true after each iteration of a loop • Assertion: something that can be demonstrated as being true or false • For our purposes (the study of robots) • Loop invariants will be assertions about the robot’s world
After one iteration we consider: • Has the direction the robot is facing changed? (How?) • Has the robot’s relative position in the world changed? (How?) • This may involve thinking about wall segments • Has the number of beepers in the beeper bag changed? (How?) • Has the number and location of other beepers in the world changed? (How?)
while (frontIsCLear()) { move(); pickBeeper(); } What can we assert? Direction is unchanged Position advanced one corner New corner has one less beeper Beeper-bag has one more beeper Bold, italic assertions are interesting Interesting means which items are important for the problem being solved clearAllBeepersToTheWall()
Interesting assertions • A loop invariant captures the interesting change during one iteration of the loop • clearAllBeepersToTheWall() invariant: • Robot has advanced one corner and removed one beeper from that corner • What else have we learned? • When the loop ends the front will be blocked • Therefore, after the loop, the robot will have removed one beeper from each corner it has passed, and the robot’s front is blocked • As long as each corner has one beeper on it, the loop has solved the problem of picking up beepers to the wall
Uses for loop invariants • For analysis (we have done this) • Powerful tools in aiding our understanding of how a loop is operating and what it will cause a robot to do • Key: How does the robot change the state of the world? • Once we know the invariant, we can use it and the terminating condition to determine if the loop solves the problem • For building loops (we will do this next) • What instructions do we want to use in a loop body?
A robot is searching for a beeper that is an unknown distance directly in front of it and there may be one-block long wall segments in the way What should be true when the loop terminates? Next to a beeper What is the invariant The robot has moved one and only one block forward so that each corner can be inspected findBeeper(): Problem statement
While (! nextToABeeper()) { move(); } Terminating condition is correct Problem with the body Will this maintain the invariant? But what situations may be true in the world that could cause error-shutoffs? findBeeper(): First Pass
While (! nextToABeeper()) { if (frontIsClear()) { move(); } else { avoidWall(); } } Terminating condition is correct Does this correct the body? Will this maintain the invariant? Does this handle the problem of the wall segments ? In designing avoidWall() we must keep the loop invariant in mind Make sure the robot advances only one corner findBeeper(): Second Pass