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

147
CHAPTER 4 RECURSION

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

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”);