chapter 4 recursion. basically, a function is recursive if it includes a call to itself

147
CHAPTER 4 RECURSION

Upload: chad-williamson

Post on 04-Jan-2016

235 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

CHAPTER 4

RECURSION

Page 2: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BASICALLY, A FUNCTION IS

RECURSIVE IF IT INCLUDES A CALL TO

ITSELF.

Page 3: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

if simplest caseSolve directly

elseMake a recursive call to a simpler case

Page 4: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

CONSIDER RECURSION WHEN

1. SIMPLEST CASE(S) CAN BE

SOLVED DIRECTLY;

2. COMPLEX CASES CAN BE

SOLVED IN TERMS OF SIMPLER

CASES OF THE SAME FORM.

Page 5: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 1: FACTORIALS

Page 6: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

GIVEN A NON-NEGATIVE INTEGER n,

n!, READ “n FACTORIAL”, IS THE

PRODUCT OF ALL INTEGERS

BETWEEN n AND 1, INCLUSIVE.

3! = 3 * 2 * 1 = 6

5! = 5 * 4 * 3 * 2 * 1 = 120

1! = 1

0! = 1 // BY DEFINITION

Page 7: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR n > 1, WE CAN CALCULATE n! IN

TERMS OF (n – 1)!

5! = 5 * 4!

4! = 4 * 3!

3! = 3 * 2!

2! = 2 * 1!

1! = 1 calculate directly

Page 8: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WE CAN THEN WORK BACK UP:

2! = 2 * 1! = 2 * 1 = 2

3! = 3 * 2! = 3 * 2 = 6

4! = 4 * 3! = 4 * 6 = 24

5! = 5 * 4! = 5 * 24 = 120

Page 9: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: n >= 0.// Postcondition: The value returned is n!, the product of// all integers between 1 and n, inclusive. long factorial (int n){ if (n == 0 || n == 1) return 1; else return n * factorial (n - 1);} // factorial

Page 10: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXECUTION FRAMES ALLOW YOU TOSEE WHAT HAPPENS DURING THEEXECUTION OF A RECURSIVEFUNCTION.

EACH FRAME IS A BOX WITHINFORMATION (SUCH ASPARAMETER VALUES) RELATED TOONE CALL TO THE FUNCTION.

Page 11: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR EXAMPLE, HERE ARE THE

EXECUTION FRAMES GENERATED,

STEP-BY-STEP, AFTER AN INITIAL

CALL OF factorial (3). AT EACH STEP,

THE TOP FRAME PERTAINS TO THE

CALL BEING EXECUTED.

Page 12: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Step 0:

n = 3

return 3 * factorial(2);

Page 13: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Step 1:

n = 2

return 2 * factorial(1);

n = 3

return 3 * factorial(2);

Page 14: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Step 2:

1n = 2

return 2 * factorial(1);

n = 3

return 3 * factorial(2);

n = 1

return 1;

Page 15: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Step 3:

2

n = 2

return 2 * 1;

n = 3

return 3 * factorial(2);

Page 16: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Step 4:

6

n = 3

return 3 * 2;

Page 17: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANALYSIS:

THE KEY TO ESTIMATING EXECUTION

TIME AND SPACE IS THE NUMBER OF

RECURSIVE CALLS TO factorial.

Page 18: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

NUMBER OF RECURSIVE CALLS

= MAXIMUM HEIGHT OF

EXECUTION FRAMES – 1

= n- 1

SO worstTime(n) IS LINEAR IN n. THAT

IS, O(n) IS THE SMALLEST UPPER

BOUND OF worstTime(n).

Page 19: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN GENERAL, worstTime(n) DEPENDS

ON ONLY TWO THINGS:

1. THE NUMBER OF LOOP

ITERATIONS AS A FUNCTION OF n;

2. THE NUMBER OF RECURSIVE

CALLS AS A FUNCTION OF n.

Page 20: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN EACH CALL TO factorial, SOME

INFORMATION MUST BE SAVED

(RETURN ADDRESS, VALUE OF n).

Page 21: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE THERE ARE n – 1

RECURSIVE CALLS, THE NUMBER OF

VARIABLES NEEDED IN ANY TRACE

OF THIS FUNCTION IS LINEAR IN n.

Page 22: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN OTHER WORDS, worstSpace(n) IS

LINEAR IN n.

AverageTime(n)? averageSpace(n)?

Page 23: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANY PROBLEM THAT CAN BE

SOLVED RECURSIVELY CAN ALSO BE

SOLVED ITERATIVELY.

AN ITERATIVE FUNCTION IS ONE

THAT HAS A LOOP STATEMENT.

Page 24: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: n >= 0.// Postcondition: The value returned is n!, the product of// all integers between 1 and n, inclusive.long factorial (int n){ int product = n;

if (n == 0)return 1;

for (int i = n -1; i > 1; i--) product = product * i;

return product;} // function factorial

Page 25: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE NUMBER OF LOOP ITERATIONS IS

n – 1.

Page 26: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SO worstTime(n) IS LINEAR IN n.

Page 27: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE NUMBER OF VARIABLES USED IN

ANY TRACE OF THIS FUNCTION IS 3.

SO worstSpace(n) IS CONSTANT.

Page 28: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

TO TRACE THE EXECUTION OF THE

RECURSIVE FACTORIAL FUNCTION:

http://www.cs.lafayette.edu/~collinsw/factorial/factorialins.html

Page 29: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 2: CONVERTING FROM

DECIMAL TO BINARY

Page 30: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE INPUT IS A NON-NEGATIVEDECIMAL INTEGER.

THE OUTPUT IS THE BINARYREPRESENTATION OF THAT INTEGER.

RUN THE FOLLOWING APPLET TO SEETHE USER’S VIEW:

http://www.cs.lafayette.edu/~collinsw/writebinary/binary.html

Page 31: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

PRINT THE BINARY EQUIVALENT OF

34:

THE RIGHTMOST BIT IS 34 % 2 = 0;

THE OTHER BITS ARE THE BINARY

EQUIVALENT OF 34 / 2, WHICH IS 17.

Page 32: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

PRINT THE BINARY EQUIVALENT OF17:

THE RIGHTMOST BIT IS 17 % 2 = 0;

THE OTHER BITS ARE THE BINARYEQUIVALENT OF 17 / 2, WHICH IS 8.

Page 33: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

34 % 2 = 0 034 / 2 = 17

17 % 2 = 1 117 / 2 = 8

8 % 2 = 0 08 / 2 = 4

4 % 2 = 0 04 / 2 = 2

2 % 2 = 0 02 / 2 = 1 1

READ BITS FROM BOTTOM TO TOP:

100010

Page 34: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WE NEED TO PRINT THE BINARY

EQUIVALENT OF n / 2 BEFORE WE

PRINT n % 2. OTHERWISE, THE

OUTPUT WILL BE IN REVERSE ORDER.

Page 35: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

STOP WHEN n = 1 OR 0, AND

OUTPUT n.

Page 36: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: n >= 0.// Postcondition: The binary equivalent of n has been// printed.void writeBinary (int n){ if (n == 0 || n == 1) cout << n; else { writeBinary (n / 2); cout << n % 2; } // else} // writeBinary

Page 37: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANALYSIS:

FOR n > 0, THE NUMBER OF

RECURSIVE CALLS IS THE NUMBER

OF TIMES THAT n CAN BE DIVIDED BY

2 UNTIL n = 1.

Page 38: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ACCORDING TO THE SPLITTING RULE

IN CHAPTER 3, THAT NUMBER IS

floor(log2 n).

SO worstTime(n) IS LOGARITHMIC IN n.

Page 39: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WHAT ABOUT worstSpace(n)?

Page 40: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE worstSpace(n) IS

PROPORTIONAL TO THE NUMBER OF

RECURSIVE CALLS, worstSpace(n) IS

LOGARITHMIC IN n.

Page 41: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

TO TRACE THE EXECUTION OF THE

RECURSIVE writeBinary METHOD:

http://www.cs.lafayette.edu/~collinsw/cs103/chapters/cpp/ch4/writeBinary/w riteBinary.html

Page 42: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXERCISE: USE EXECUTION FRAMES

TO TRACE THE EXECUTION OF

writeBinary (20);

Page 43: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 3: TOWERS OF HANOI

Page 44: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

GIVEN 3 POLES (A, B, C) AND n DISKS

OF INCREASING SIZE (1, 2, 3, …, n),

MOVE THE n DISKS FROM POLE A TO

POLE B. USE POLE C FOR

TEMPORARY STORAGE.

Page 45: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

1. ONLY ONE DISK MAY BE MOVED

AT ANY TIME.

2. NO DISK MAY EVER BE PLACED ON

TOP OF A SMALLER DISK.

3. OTHER THAN THE PROHIBITION

OF RULE 2, THE TOP DISK ON ANY

POLE MAY BE MOVED TO EITHER

OF THE OTHER POLES.

Page 46: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

INITIALLY, WITH 4 DISKS:

1 2 3 4

A B C

Page 47: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

INSTEAD OF TRYING TO FIGURE

OUT WHERE TO MOVE DISK 1, LET’S

LOOK AT THE PICTURE JUST

BEFORE DISK 4 IS MOVED:

Page 48: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

JUST BEFORE DISK 4 IS MOVED: 1 2 4 3

A B C

Page 49: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SO WE WILL BE ABLE TO MOVE 4

DISKS FROM ONE POLE TO ANOTHER

IF WE ARE ABLE TO FIGURE OUT

HOW TO MOVE 3 DISKS FROM ONE

POLE TO ANOTHER (AHA!).

TO MOVE 3 DISKS …

Page 50: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IF n = 1, MOVE DISK 1 FROM POLE ‘A’ TO POLE

‘B’.

OTHERWISE,

1. MOVE n – 1 DISKS FROM ‘A’ TO ‘C’, WITH ‘B’

AS A TEMPORARY.

2. MOVE DISK n FROM ‘A’ TO ‘B’.

3. MOVE n – 1 DISKS FROM ‘C’ TO ‘B’, WITH ‘A’

AS A TEMPORARY.

Page 51: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR THE SAKE OF GENERALITY, USE

VARIABLES INSTEAD OF

CONSTANTS FOR THE POLES:

orig = ‘A’dest = ‘B’temp = ‘C’

HERE IS THE STRATEGY TO MOVE n

DISKS FROM orig TO dest:

Page 52: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IF n = 1, MOVE DISK 1 FROM orig TO dest.

OTHERWISE,

MOVE n-1 DISKS FROM orig TO temp.

MOVE DISK n FROM orig TO dest.

MOVE n-1 DISKS FROM temp TO dest

Page 53: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: n > 0.// Postcondition: The steps needed to move n disks from pole orig // to pole dest have been written out. Pole temp // is used for temporary storage. // The worstTime(n) is O(2 n).void move (int n, char orig, char dest, char temp){ if (n == 1) cout << "Move disk 1 from " << orig << " to " << dest << endl; else { move (n ‑ 1, orig, temp, dest); cout << "Move disk " << n << " from " << orig << " to " << dest << endl; move (n ‑ 1, temp, dest, orig) ; } // else} // move

Page 54: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANALYSIS:

worstTime(n) # OF CALLS TO move

Page 55: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

move (n, …)

move (n-1, …) move (n-1, …)

move (n-2, …) move (n-2, …) move (n-2, …) move (n-2, …)

… … … … … … … …

move (1, …) move (1, …) …

Page 56: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THERE ARE n LEVELS IN THIS TREE.

THE NUMBER OF CALLS TO move AT LEVEL 0 IS 1 = 20

THE NUMBER OF CALLS TO move AT LEVEL 1 IS 2 = 21

THE NUMBER OF CALLS TO move AT LEVEL 2 IS 4 = 22

THE NUMBER OF CALLS TO move AT LEVEL n-1 IS 2n-1

Page 57: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE TOTAL NUMBER OF CALLS TO move IS:

n-1

1 + 2 + 4 + … + 2 n-1 = 2i

i=0

Page 58: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

n-1

2i = 2n - 1

i=0

SEE EXAMPLE 6 OF APPENDIX 1 FOR A

PROOF BY MATHEMATICAL

INDUCTION.

Page 59: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WE CONCLUDE THAT worstTime(n) is

O(2n), AND, BECAUSE 2n - 1 DISKS MUST

BE MOVED, O(2n) IS THE SMALLEST

UPPER BOUND OF worstTime(n).

Page 60: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE n APPEARS AS THE

EXPONENT IN THE ESTIMATE OF

worstTime(n), WE SAY THAT

worstTime(n) IS EXPONENTIAL IN n.

WHENEVER POSSIBLE, AVOID

METHODS THAT TAKE EXPONENTIAL

TIME.

Page 61: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

TO TRACE THE EXECUTION OF THIS

RECURSIVE move FUNCTION:

http://www.cs.lafayette.edu/~collinsw/hanoi2/hanoiins.html

Page 62: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 4:

BACKTRACKING

Page 63: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BACKTRACKING IS THE STRATEGY

OF TRYING TO REACH A GOAL BY A

SEQUENCE OF CHOSEN POSITIONS,

WITH RE-TRACING IN REVERSE

ORDER OF POSITIONS THAT

CANNOT LEAD TO THE GOAL.

Page 64: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

      

      

STRATEGY: TRY TO GO WEST; IF UNABLE TO GO WEST,

TRY TO GO SOUTH; IF UNABLE TO GO SOUTH,

BACKTRACK (UNTIL YOU CAN GO SOUTH). THE GOAL IS

EITHER G1 OR G2.

P3 P2 P1

P4 P5

G2 P7 P6

G1

Page 65: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WHEN A POSITION IS VISITED, IT IS

MARKED AS (POTENTIALLY) BEING ON

A PATH TO THE GOAL. IF WE

DISCOVER OTHERWISE, THE

MARKING MUST BE UNDONE, SO THAT

POSITION WILL NEVER AGAIN BE

VISITED. FOR EXAMPLE, P5 IS NOT

VISITED FROM P8.    

Page 66: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

WE WILL SOLVE THIS MAZE-SEARCH

PROBLEM WITHIN THE GENERAL

FRAMEWORK OF BACKTRACKING,

WHICH CAN EASILY BE UTILIZED IN

OTHER APPLICATIONS.    

Page 67: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

  

ALREADY PROVIDED: Application.h (methods such as valid, record, done, undo)

GENERAL-PURPOSE Backtrack CLASS;

main FUNCTION;

USER SUPPLIES: A SOURCE FILE THAT IMPLEMENTS THE HEADER FILE Application.h;

A Position CLASS    

Page 68: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

class Application{

friend ostream& operator<< (ostream& stream, Application& app);

public:

// Postcondition: the initial state for this Application has // been generated -- from input or // assignments -- and the start position // has been returned.

Position generateInitialState();

// Postcondition: true has been returned if pos can be // on the path to a goal. Otherwise, // false has been returned.

bool valid (const Position& pos);

Page 69: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: pos represents a valid position. // Postcondition: pos has been recorded as a valid position. void record (const Position& pos);

// Postcondition: true has been returned if pos is the final // position for this application. Otherwise, // false has been returned.

bool done (const Position& pos);

// Postcondition: pos has been marked as not being on the // path to a goal.

void undo (const Position& pos);

Page 70: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EMBEDDED WITHIN THE Application

CLASS IS AN Iterator CLASS FOR

MANEUVERING THROUGH THE

APPLICATION.

Page 71: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

class Iterator{ public: // Postcondition: this Iterator has been initialized to

// iterate from pos. Iterator (const Position& pos);

// Postcondition: the next position for this Iterator has // been returned.

Position operator++ (int);

// Postcondition: this Iterator cannot iterate any further // from the current position.

bool atEnd();protected:

void* fieldPtr; // explained later}; // class Iterator

Page 72: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE Iterator CLASS’S FIELDS WILL

VARY FROM ONE APPLICATION TO

THE NEXT, SO WE DEFINE A DUMMY

FIELD, fieldPtr, THAT WILL POINT TO

THE REAL FIELDS WHEN WE GET TO A

SPECIFIC APPLICATION.

Page 73: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE IS THE DECLARATION OF THE

BackTrack CLASS:

Page 74: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

class BackTrack{ protected: Application app;

public:// Postcondition: this BackTrack object has been// initialized from app.

BackTrack (const Application& app);

// Postcondition: a solution going through pos has been// attempted. If that attempt was// successful, true has been returned.// Otherwise, false has been returned.

bool tryToSolve (Position pos);}; // class BackTrack

Page 75: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE tryToSolve METHOD FIRST

CONSTRUCTS AN ITERATOR FROM pos,

AND THEN LOOPS UNTIL SUCCESS HAS

BEEN ACHIEVED OR NO MORE

ITERATIONS ARE POSSIBLE.

Page 76: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EACH LOOP ITERATION CONSIDERS THREE

POSSIBILITIES FOR THE NEW POSITION

GENERATED BY THE ITERATOR:

1. GOAL REACHED! RETURN true.

2. VALID POSITION BUT NOT THE GOAL; THEN

CALL tryToSolve TO SEE IF SUCCESS IS

POSSIBLE FROM THE CURRENT VALUE OF

pos.

3. INVALID POSITION AND ITERATOR AT END;

RETURN false.

Page 77: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

bool BackTrack:::tryToSolve (Position pos){ bool success = false; Application::Iterator itr (pos); while (!success && !itr.atEnd()) { pos = itr++ if (app.valid (pos)) { app.record (pos); if (app.done (pos)) success = true; else { success = tryToSolve (pos); if (!success) app.undo (pos); } // not done } // a valid position } // while return success;} // method tryToSolve

Page 78: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE main FUNCTION INITIALIZES THE

APPLICATION BY CALLING THE

generateInitialState METHOD, WHICH

RETURNS THE START POSITION. THE

CALL TO tryToSolve (start) RESULTS IN

SUCCESS OR FAILURE.

Page 79: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Application app; BackTrack b (app);

cout << INITIAL_STATE; Position start = app.generateInitialState(); cout << app; if (!app.valid (start)) cout << FAILURE << endl; else { app.record (start); if (app.done (start) || b.tryToSolve (start)) cout << SUCCESS << endl << app; else { app.undo (start); cout << FAILURE << endl; } // failure } // start is valid

Page 80: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

MAZE SEARCHING: 1 = CORRIDOR; 0 = WALL

start

1 1 1 0 1 1 0 0 0 1 1 1 11 0 1 1 1 0 1 1 1 1 1 0 11 0 0 0 1 0 1 0 1 0 1 0 11 0 0 0 1 1 1 0 1 0 1 1 11 1 1 1 1 0 0 0 0 1 0 0 00 0 0 0 1 0 0 0 0 0 0 0 00 0 0 0 1 1 1 1 1 1 1 1 1 finish

ITERATOR CHOICES: NORTH, EAST, SOUTH, WEST

Page 81: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

TO WATCH A SOLUTION BEING CREATED:

http://www.cs.lafayette.edu/~collinsw/maze/MazeApplet.html

TO RETRIEVE THE PROJECT SO YOU CAN RUN IT:

http://www.cs.lafayette.edu/~collinsw/cs103/chapters/cpp/ch4/Maze.html

Page 82: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SOLUTION: 9 = PATH; 2 = DEAD END

9 9 9 0 2 2 0 0 0 2 2 2 21 0 9 9 9 0 2 2 2 2 2 0 21 0 0 0 9 0 2 0 2 0 2 0 21 0 0 0 9 2 2 0 2 0 2 2 21 1 1 1 9 0 0 0 0 1 0 0 00 0 0 0 9 0 0 0 0 0 0 0 00 0 0 0 9 9 9 9 9 9 9 9 9

Page 83: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ALL THAT NEED TO BE DEVELOPED

ARE THE Position CLASS AND THE

SOURCE FILE THAT IMPLEMENTS

Application.h.

FOR THIS APPLICATION, A POSITION IS

SIMPLY A ROW AND COLUMN, SO:

Page 84: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

class Position{ public: Position( ); Position (int row, int column);

void setPosition (int row, int column); int getRow( ); int getColumn( );

protected: int row, column;}; // class Position

Page 85: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE DEFINITIONS OF THE Position

METHODS ARE STRAIGHTFORWARD.

FOR EXAMPLE:

int Position::getRow( ){ return row;} // method getRow( )

Page 86: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR THIS APPLICATION, Maze.cpp

IMPLEMENTS THE Application CLASS,

WITH A GRID TO HOLD THE MAZE.

IF THE MAZE IS “HARD-WIRED”

INSTEAD OF BEING READ IN, WE

HAVE THE FOLLOWING:

Page 87: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

short grid[ROWS][COLUMNS] ={ {1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1}, {1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}, {1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1}, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; // grid

Position start, finish;

THESE ARE NOT FIELDS: THERE IS IS ONLY ONEgrid, start, AND finish FOR THE APPLICATION.

Page 88: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE, FOR EXAMPLE, IS THE

DEFINITION OF valid:

bool Application::valid (const Position& pos){ if (pos.getRow() >= 0 && pos.getRow() < ROWS && pos.getColumn() >= 0 &&

pos.getColumn() < COLUMNS && grid [pos.getRow()][pos.getColumn()] == CORRIDOR) return true; return false;} // method valid

Page 89: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FINALLY, WE DEFINE THE EMBEDDED

Iterator CLASS. A NEW Iterator OBJECT

IS CONSTRUCTED WITH EACH CALL

TO tryToSolve. SO WE CANNOT GET BY

WITH LOCAL VARIABLES IN Maze.cpp:

WE NEED FIELDS.

Page 90: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

A CLASS’S FIELDS MUST BE DEFINED

IN THE HEADER FILE, NOT IN THE

SOURCE FILE. BUT THE HEADER FILE

CANNOT CONTAIN ANY APPLICATION-

SPECIFIC INFORMATION!

Page 91: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE SOLUTION IS TO DEFINE A

GENERIC POINTER, fieldPtr, IN

Application.h, AND THEN HAVE IT POINT

TO THE “REAL FIELDS” IN Maze.cpp.

FROM Application.h:

void* fieldPtr;

Page 92: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN Maze.cpp, WE DEFINE

struct itrFields{ int row, column, direction; // 0 = north, 1 = east, 2 = south, 3 = west};

THE Iterator CONSTRUCTOR ASSIGNS

A VARIABLE OF THIS TYPE TO fieldPtr,

AND operator++ (int) AND THE atEnd( )

METHOD UTILIZE *fieldPtr.

Page 93: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Application::Iterator::Iterator (Position pos){ itrFields* itrPtr = new itrFields; itrPtr -> row = pos.getRow(); itrPtr -> column = pos.getColumn(); itrPtr -> direction = 0; fieldPtr = itrPtr;} // constructor

bool Application::Iterator::atEnd( ){ return ((itrFields*)fieldPtr) -> direction >= 3;} // method atEnd

Page 94: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Position Application::Iterator::operator++ (int){ itrFields* itrPtr = (itrFields*)fieldPtr; int nextRow = itrPtr -> row, nextColumn = itrPtr -> column; switch (itrPtr -> direction++) { case 0: nextRow = itrPtr -> row - 1; // north break; case 1: nextColumn = itrPtr -> column + 1; // east break; case 2: nextRow = itrPtr -> row + 1; // south break; case 3: nextColumn = itrPtr -> column - 1; // west } // switch; Position next (nextRow, nextColumn); return next;} // operator++ (int)

Page 95: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE fieldPtr IS A FIELD IN THE

Iterator CLASS, EACH Iterator OBJECT

HAS ITS OWN COPY OF fieldPtr.

Page 96: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXERCISE: RECALL THE SOLUTION WHEN THE ORDER WAS NORTH, EAST, SOUTH, WEST:

9 9 9 0 2 2 0 0 0 2 2 2 21 0 9 9 9 0 2 2 2 2 2 0 21 0 0 0 9 0 2 0 2 0 2 0 21 0 0 0 9 2 2 0 2 0 2 2 21 1 1 1 9 0 0 0 0 1 0 0 00 0 0 0 9 0 0 0 0 0 0 0 00 0 0 0 9 9 9 9 9 9 9 9 9

Page 97: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

RE-SOLVE WITH THE ORDER NORTH, EAST, WEST, SOUTH:

start 1 1 1 0 1 1 0 0 0 1 1 1 11 0 1 1 1 0 1 1 1 1 1 0 11 0 0 0 1 0 1 0 1 0 1 0 11 0 0 0 1 1 1 0 1 0 1 1 11 1 1 1 1 0 0 0 0 1 0 0 00 0 0 0 1 0 0 0 0 0 0 0 00 0 0 0 1 1 1 1 1 1 1 1 1 finish

HINT: ONLY ONE ‘1’ REMAINS.

Page 98: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 5:

SEARCHING AN ARRAY

Page 99: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SEQUENTIAL SEARCH OF AN ARRAY

FOR AN ITEM:

START AT INDEX 0: COMPARE EACH

ITEM IN THE ARRAY TO THE ITEM

SOUGHT UNTIL SUCCESS (ITEM

FOUND) OR FAILURE (END OF ARRAY

REACHED).

Page 100: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

A SEQUENTIAL SEARCH IS THE BASIS

FOR THE GENERIC ALGORITHM find:

template <class InputIterator, class T>InputIterator find (InputIterator first, InputIterator last,

const T& value){ while (first != last && *first != value) ++first; return first;}

Page 101: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THIS ALGORITHM WORKS WITH

ARRAYS AS WELL AS WITH

CONTAINER OBJECTS.

string words [20];string* wordPtr = find (words, words + 20, myWord);

cout << myWord;if (wordPtr != words + 20)

cout << “ at index “ << (wordPtr – words) << endl;else cout << “ not found.” << endl; POINTER

ARITHMETIC

Page 102: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Linked<int> myLinked;Linked<int>::Iterator itr;

Itr = find (myLinked.begin( ), myLinked.end( ), someInt);cout << someInt;if (itr != myLinked.end( ))

cout << “ found “ << endl;else cout << “ not found.” << endl;

Page 103: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE worstTime(n) IS LINEAR IN n.

THE averageTime(n) IS LINEAR IN n.

Page 104: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BINARY SEARCH:

DURING EACH ITERATION, THE SIZE

OF THE SUBARRAY SEARCHED IS

DIVIDED BY 2 UNTIL SUCCESS OR

FAILURE OCCURS.

NOTE: THE ARRAY MUST BE SORTED!

Page 105: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

// Precondition: The array, from first to just before last,// is sorted according to operator<.// Postcondition: true has been returned if value occurs in// the array from first to just before last.// Otherwise, false has been returned.// The worstTime(n) is O(log n).template<class T>bool binary_search (T* first, T* last, const T& value);

Page 106: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

first POINTS TO THE FIRST LOCATION

OF THE REGION OF THE ARRAY TO

BE SEARCHED, AND last POINTS

ONE BEYOND

THE LAST LOCATION OF THE REGION

OF THE ARRAY TO BE SEARCHED.

Page 107: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR EXAMPLE, SUPPOSE THE ARRAY

CONSISTS OF 20 intS, WITH VALUES 0

THROUGH 19:

first last

0 1 … 19

Page 108: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE IS THE BASIC STRATEGY:

T* middle = first + (last - first) / 2;

IF (*middle < value)SEARCH FROM middle + 1 TO last – 1;

ELSE IF (value < *middle)SEARCH FROM first TO middle – 1;

ELSEreturn true;

Page 109: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE SEARCH WILL STOP IF EITHER

true IS RETURNED OR IF THE REGION

TO BE SEARCHED IS EMPTY, THAT IS,

IF first >= last.

HERE IS THE DEFINITION:

Page 110: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

template<class T>bool binary_search (T* first, T* last, const T& value){ if (first >= last) return false; T* middle = (first + last) / 2; if (*middle < value) return binary_search (middle + 1, last, value); else if (value < *middle) return binary_search (first, middle, value); return true;} // binary_search

Page 111: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SUPPOSE THE ARRAY a CONTAINS

a [0] ANDREWa [1] BRANDONa [2] CHRISa [3] CHUCKa [4] GEOFFa [5] JASONa [6] MARGARETa [7] MARKa [8] MATTa [9] ROBa [10] SAMIRA

Page 112: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

DETERMINE THE SUCCESSIVE

VALUES FOR *first, *(last – 1), AND

*middle IF THE CALL IS

binary_search (a, a + 11, “MARK”);

Page 113: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

DETERMINE THE SUCCESSIVE

VALUES FOR *first, *(last – 1), AND

*middle IF THE CALL IS

binary_search (a, a + 11, “CARLOS”);

Page 114: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

Binary Search Tester Applet:

http://www.cs.lafayette.edu/~collinsw/chapters/ch4/binaryS earch/binaryins.html

Page 115: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANALYSIS: LET n = SIZE OF INITIAL

REGION TO BE SEARCHED.

UNSUCCESSFUL SEARCH:

KEEP DIVIDING n BY 2 UNTIL n = 0.

Page 116: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

UNSUCCESSFUL SEARCH

THE NUMBER OF DIVISIONS WILL BE:

floor(log2n) + 1

Page 117: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

UNSUCCESSFUL SEARCH

SO worstTime(n) IS LOGARITHMIC IN n.

Page 118: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

UNSUCCESSFUL SEARCH

THE averageTime(n) IS ALSO

LOGARITHMIC IN n BECAUSE, FOR

AN UNSUCCESSFUL SEARCH, THE

ALGORITHM TERMINATES ONLY

WHEN n = 0.

Page 119: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SUCCESSFUL SEARCH:

WORST CASE: KEEP DIVIDING BY n

UNTIL n = 1. THEN first = last – 1 =

middle.

Page 120: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SUCCESSFUL SEARCH

THE worstTime(n) IS LOGARITHMIC IN n.

Page 121: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SUCCESSFUL SEARCH

THE averageTime(n) IS LOGARITHMIC

IN n. (SEE EXERCISE 4.13.)

Page 122: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

SEE LAB 11 FOR AN ITERATIVE

VERSION THAT IS:

1. SLIGHTLY FASTER;

2. MORE VERSATILE;

3. IN THE STANDARD TEMPLATELIBRARY.

Page 123: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXAMPLE 7:

GENERATING PERMUTATIONS

Page 124: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

A PERMUTATION IS AN ARRANGEMENT

OF ITEMS IN A LINEAR ORDER.

Page 125: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE ARE THE SIX PERMUTATIONS OF

THE STRING “123”:

123132213231312321

Page 126: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN GENERAL, FOR n CHARACTERS,

THERE ARE n CHOICES FOR THE FIRST

CHARACTER IN A PERMUTATION. FOR

EACH OF THESE n CHOICES, THERE

ARE n – 1 CHOICES FOR THE SECOND

CHARACTER. AND SO ON.

Page 127: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE TOTAL NUMBER OF

PERMUTATIONS OF A STRING OF n

CHARACTERS IS

n (n – 1) (n – 2) … 2 = n!

Page 128: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE IS THE INTERFACE FOR A

FUNCTION TO PRINT ALL

PERMUTATIONS OF A STRING:

// Postcondition: all the permutations of s have been printed.void permute (const string& s);

Page 129: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

TO PRINT ALL PERMUTATIONS OF A

STRING OF n CHARACTERS, THE

INITIAL STRATEGY IS THIS: FOR EACH

OF THE n POSSIBLE VALUES FOR THE

FIRST CHARACTER, WE PRINT THE

(n – 1)! PERMUTATIONS THAT START

WITH THAT CHARACTER.

Page 130: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THIS STRATEGY REDUCES THE

PROBLEM OF PRINTING ALL

PERMUTATIONS OF n CHARACTERS TO

THE PROBLEM OF PRINTING ALL

PERMUTATIONS OF n – 1

CHARACTERS.

Page 131: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THIS SUGGESTS A RECURSIVE

FUNCTION, WITH A for STATEMENT

TO LOOP THROUGH THE RANGE OF

CHARACTER VALUES, AND A

RECURSIVE CALL WITHIN THAT for

LOOP.

Page 132: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR EXAMPLE, IF WE START WITH

“123”, WE MAKE A RECURSIVE CALL

TO PRINT ALL PERMUTATIONS THAT

START WITH ‘1’.

Page 133: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THEN, IN “123”, WE SWAP ‘1’ AND ‘2’

TO GET “213”, AND RECURSIVELY

PRINT ALL PERMUTATIONS THAT

START WITH ‘2’.

FINALLY, IN “213”, WE SWAP ‘2’ AND ‘3’

TO GET “312”, AND RECURSIVELY

PRINT ALL PERMUTATIONS THAT

START WITH ‘3’.

Page 134: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE INITIAL CALL PRINTS ALL

PERMUTATIONS OF THE STRING s

WITH s[0] FIXED. THE CORRESPON-

DING RECURSIVE CALLS PRINT ALL

PERMUTATIONS OF THE STRING s

WITH s [0] AND s [1] FIXED, THEN WITH

s [0], s [1], AND s [2] FIXED, AND SO ON.

Page 135: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE THE STARTING INDEX FOR

PERMUTING VARIES WITH EACH CALL,

THE permute FUNCTION WILL SIMPLY

BE A WRAPPER FOR THE RECURSIVE

FUNCTION.

// Postcondition: all the permutations of s have been printed.void permute (const string& s){ rec_permute (s, 0);} // permute

Page 136: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

HERE IS THE INTERFACE FOR

rec_permute:

// Postcondition: s has been printed for each permutation of// s [k . . . s.length( ) - 1].void rec_permute (string s, unsigned k);

NOTE THAT s.length( ) RETURNS AN

unsigned int.

Page 137: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BECAUSE s IS A VALUE PARAMETER, s

IS NOT ALTERED BY THE RECURSIVE

CALLS. SO AFTER “123” AND “132” ARE

PRINTED, s IS “123”. BUT s IS ALTERED

BY THE SWAPPING WITHIN THE for

LOOP:

Page 138: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

for (unsigned i = k; i < s.length(); i++){ swap (s [i], s [k]); // swap is a generic algorithm rec_permute (s, k + 1);} // for

WHEN k = s.length( ) – 1, s IS PRINTED.

THE COMPLETE DEFINITION IS:

Page 139: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

void rec_permute (string s, unsigned k){ if (k == s.length() - 1) cout << s << endl; else for (unsigned i = k; i < s.length(); i++) { swap (s [i], s [k]); // swap is a generic algorithm rec_permute (s, k + 1); } // for} // rec_permute

Page 140: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

FOR AN APPLET THAT DISPLAYS

AN EXECUTION TRACE:

http://www.cs.lafayette.edu/~collinsw/cs103/chapters/cpp/ch4/permute/permutationins.html

Page 141: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

ANALYSIS OF permute:

CLEARLY, worstTime(n) >= n!

BECAUSE n! STRINGS MUST BE

PRINTED.

Page 142: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

IN FACT – SEE CHAPTER 4 FOR

DETAILS – worstTime(n) IS O(n!).

Page 143: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

THE COST OF RECURSION

WHENEVER A FUNCTION IS CALLED,

SOME INFORMATION IS SAVED TO

PREVENT ITS DESTRUCTION IN CASE

THE CALL IS RECURSIVE. THIS

INFORMATION IS CALLED AN

ACTIVATION RECORD.

Page 144: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EACH ACTIVATION RECORD CONTAINS:

1. THE RETURN ADDRESS;

2. A COPY OF EACH ARGUMENTCORRESPONDING TO A VALUE FORMALPARAMETER;

3. THE ADDRESS OF EACH ARGUMENTCORRESPONDING TO A REFERENCE FORMALPARAMETER;

4. A COPY OF EACH OF THE FUNCTION’S OTHERLOCAL VARIABLES.

Page 145: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

AFTER THE CALL HAS BEEN

COMPLETED, THE PREVIOUS

ACTIVATION RECORD’S INFORMATION

IS RESTORED AND THE EXECUTION OF

THE CALLING FUNCTION RESUMES.

THE SAVING AND RESTORING OF

THESE RECORDS TAKES TIME.

Page 146: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

BASICALLY, AN ITERATIVE FUNCTION

WILL BE SLIGHTLY FASTER THAN ITS

RECURSIVE COUNTERPART. BUT FOR

PROBLEMS SUCH AS BACKTRACKING

AND PERMUTING, THE RECURSIVE

FUNCTIONS TAKE A LOT LESS TIME TO

DEVELOP THAN THE ITERATIVE

VERSIONS!

Page 147: CHAPTER 4 RECURSION. BASICALLY, A FUNCTION IS RECURSIVE IF IT INCLUDES A CALL TO ITSELF

EXERCISE: IN THE rec_permute

FUNCTION, SUPPOSE WE CHANGE

THE HEADING TO:

void rec_permute (string& s, unsigned k)

WHAT WOULD BE OUTPUT IF THE

ORIGINAL CALL WEREpermute (“ABC”);