1 applications of recursion (walls & mirrors - chapter 5)

41
1 Applications of Recursion (Walls & Mirrors - Chapter 5)

Post on 22-Dec-2015

234 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

1

Applications of Recursion

(Walls & Mirrors - Chapter 5)

Page 2: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

2

Overview

• Writing a Linked List Backwards

• Recursive Insert

• N Queens Problem

• Recognizing Simple Languages

• Infix, Prefix, and Postfix Expressions

• Translating Prefix Expressions into Postfix

Page 3: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

3

Writing a Linked List Backwards

For a singly-linked list, this is difficult to do iteratively, but easy to do recursively.

Page 4: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

4

Writing a Linked List Backwards (Cont’d.)

struct ListNode{ int value; ListNode *next;};ListNode *head;

void writeBackwards( ListNode *pnode ){ if( pnode != NULL ) { writeBackwards( pnode -> next ); cout << pnode -> value << endl; }}

head

13 21 34

pnode

writeBackwards( head );

Page 5: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

5

Recursive Insert

Let’s reconsider insertion into a sorted list -- recursively!

insert( &head, 8 );

insert( &head, 13);

head 21 34

Page 6: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

6

Recursive Insert: At Head of Listvoid insert( ListNode **pnode, const int newValue ){ if( *pnode = = NULL | | newValue < (*pnode) -> value ) { ListNode *newNode = new ListNode;

newNode -> value = newValue; newNode -> next = *pnode; *pnode = newNode; } else . . .}

newValue8

21

pnode 8

34head

Page 7: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

7

Recursive Insert: After Head of Listvoid insert( ListNode **pnode, const int newValue ){ if( *pnode = = NULL | | newValue < (*pnode) -> value ) { ListNode *newNode = new ListNode;

newNode -> value = newValue; newNode -> next = *pnode; *pnode = newNode; } else insert( &( (*pnode) -> next), newValue );}

newValue13

head 8 21 34

pnode

Page 8: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

8

Recursive Insert: Summary

This code for recursive insertion into a singly-linked list has about 1/3 the number of statements required for the non-recursive solution. (6 statements vs. 17 statements)

Page 9: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

9

N Queens Problem

• 8 Queens Problem: Given an 8 x 8 chessboard, place 8 queens on the board so that no queen can attack any other.

• Consider a generalization of this with N queens and a board of N x N squares.

• We shall describe a way to solve this problem using a technique called backtracking.

Page 10: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

10

Backtracking

• Backtracking is a problem-solving strategy that, when it reaches an impasse, retraces its steps in reverse order before trying a new sequence of steps.

• This is like organized, trial and error:

– The same thing is never considered twice, and

– If the domain of possible solutions is finite, we ensure that we eventually try all possible solutions.

Page 11: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

11

Queen’s Possible Attacks

A queen in chess can attack horizontally (left and right),

vertically (up and down), and on both diagonals.

Q

Page 12: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

12

N Queens: N = 2

A search through all possible configurations yields

no solution!

Q Q Q

Q

Q

Q

Q

Q

Q

Q Q Q

Page 13: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

13

N Queens: N = 4

• One possible solution for N = 4 looks like this.

• Observation: To place N queens on an N x N board so that none is under attack, each queen must be in its own row and column.

Q

Q

Q

Q

Page 14: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

14

N Queens: Solution Strategy

1) Start with a queen in the 1st row and 1st column.

2) Place the 2nd queen in the 2nd column, at the first row where this queen will not be under attack.

3) Repeat step (2) with additional queens until the problem is solved or, it is not possible to place a queen in a column without being attacked.

4) If step (3) failed to place a queen in a column, then backup to the previous column and move that queen to the next, unattacked row.

5) Repeat steps (3) and (4) until the problem is solved or, there are no more possibilities for placing a queen in the 1st column. In this case, there is no solution.

Page 15: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

15

Solving N Queens with N = 3

Nowhere to place 3rd queen: need to backtrack!

Q

Q

Q Q

Q

Q Q

Q

Q

Q

Q

Q Q

Q

Q

2 queenssuccessfully placed

Page 16: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

16

Solving N Queens with N = 3 (Cont’d.)

Since the queen in the 2nd column is in the last row, there are no more alternatives for placing it. We need to backtrack to the 1st column:

Q

Q

Q

Page 17: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

17

Solving N Queens with N = 3 (Cont’d.)

QQ Q

Q

Q

Q

Nowhere to place 2nd queen: need to backtrack to the 1st column again!

Page 18: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

18

Solving N Queens with N = 3 (Cont’d.)

Q

Q

Nowhere to place 3rd queen: need to backtrack to 2nd column again.

Q

Q

QQ

Q Q

Q

Q

Q

Page 19: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

19

Solving N Queens with N = 3 (Cont’d.)

Q

Q

Q Q

• Nowhere to place 2nd queen: need to backtrack to 1st column. However, since that queen is in the last row, there are no more possibilities to consider.

• No solution to N Queens problem with N = 3.

Page 20: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

20

Solving N Queens with N = 4

A solution to the N Queens problem with N = 4

Q

Q

Q

Q

Q

Q

Q

Q

Q

Page 21: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

21

• By reflecting the preceding solution about its horizontal or vertical axis, we find an additional, alternative solution.

• If the preceding algorithm is allowed to continue, it will find this, and all other solutions that may exist.

Solving N Queens with N = 4

Q

Q

Q

Q

Q

Q

Q

Q

Page 22: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

22

N Queens: C++ Implementationbool placeQueens( int currColumn ){ if( currColumn > BOARD_SIZE ) return true;

bool queenPlaced = false; int row = 1; while( !queenPlaced && row <= BOARD_SIZE ) { if( isUnderAttack( row, currColumn ) ) row++; else { setQueen( row, currColumn ); queenPlaced = placeQueens( currColumn + 1 ); if( !queenPlaced ) { removeQueen( row, currColumn ); row++; } } } return queenPlaced;}

Page 23: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

23

Recognizing Simple Languages

• A language is a set of strings of symbols that adhere to the rules of a grammar.

• A grammar is a set rules that define a language.

• A recognizer is a mechanism that, based on a language’s grammar, determines whether a given string is in the language.

Page 24: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

24

Grammar Notation

X | Y means X or Y

X Y means X followed by Y

<word> means that word is a variable of the grammar.

Example: Grammar for non-negative integers:

<number> = <digit> | <number> <digit>

<digit> = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

means that a number is either a digit or a number followed by a digit. I.e. it is is either one of {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} or a string of symbols from {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}.

Page 25: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

25

Simple Languages: C++ Identifiers

A valid C++ identifier is a string of letters and digits, where the first character is a letter, and the underscore _ counts as a letter.

Grammar for C++ identifiers:

<identifier> = <letter> | <identifier> < letter> |

<identifier> < digit>

<letter> = a | b | c | . . . | z | A | B | C | . . . | Z | _

<digit> = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Page 26: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

26

Recognizer for C++ Identifiers

bool isIdentifier( char str[ ], int strLen )

{

if( strLen = = 0 ) return false;

if( strLen = = 1 ) return isLetter( str[0] );

if( isLetter( str[ strLen – 1 ] ) | | isDigit( str[ strLen – 1 ] ) )

return isIdentifier( str, strLen – 1 );

else

return false;

}

Page 27: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

27

Simple Languages: Palindromes

• A palindrome is a string that reads the same from left to right as right to left.

– NOON, DEED, RADAR, MADAM

– ABLE WAS I ERE I SAW ELBA

• Grammar for palindromes:

<pal> = empty string | <ch> | a <pal> a | b <pal> b | . . .

| Z <pal> Z

<ch> = a | b | c | . . . | z | A | B | C | . . . | Z

Page 28: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

28

Recognizer for Palindromes

bool isPalindrome( char str[ ], int first, int last )

{

int StrLen = last – first + 1;

if( StrLen = = 0 ) return true;

if( StrLen = = 1 ) return isChar( str[0] );

if( str[ first ] ! = str[ last ] ) return false;

return isPalindrome( str, first + 1, last – 1 );

}

Page 29: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

29

Simple Languages: AnBn

• Consider strings of the form AnBn, for some n 0:

empty string n = 0

AB n = 1

AABB n = 2

AAABBB n = 3

. . .

• Grammar:

<word> = empty string | A <word> B

Page 30: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

30

Recognizer for AnBn

bool isAnBn( char str[ ], int first, int last )

{

if( last – first < 0 ) // str[ ] contains 0 characters

return true;

if( str[ first ] = = ‘A’ && str[ last ] = = ‘B’ )

return isAnBn( str, first + 1, last – 1 );

else

return false;

}

Page 31: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

31

Infix Expressions

• An infix expression is an algebraic expression in which each binary operator appears between its two operands.

• Examples:

a + b

a + b * c

(a + b) * c

• Rules of precedence and parentheses are used to make infix expressions unambiguous.

Page 32: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

32

Prefix and Postfix Expressions

• A prefix expression is an algebraic expression in which each binary operator precedes its two operands:

+ a b

+ a * b c

* + a b c

• A postfix expression is an algebraic expression in which each binary operator follows its two operands:

a b +

a b c * +

a b + c *

Page 33: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

33

Grammars for Prefix and Postfix Expressions

• Prefix Expression Grammar:

<prefixExpr> = <identifier> |

<operator> <prefixExpr> <prefixExpr>

• Postfix Expression Grammar:

<postfixExpr> = <identifier> |

< postfixExpr> < postfixExpr> <operator>

where

<operator> = + | – | * | /

<identifier> = a | b | c | . . . | z

Page 34: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

34

Strategy for a Prefix Expression Recognizer

1) If the input string is an identifier, then return true.

2) Otherwise, if the initial part of the string is not an operator followed by a prefix expression, then return false.

3) If the initial part of the string is an operator followed by a prefix expression, then determine if the remainder of the string is a prefix expression.

4) If the remainder of the string is a prefix expression then return true, otherwise return false.

Page 35: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

35

Strategy for a Prefix Expression Recognizer

Suppose we had a function

int endPrefix( char str[ ], int first, int last )

that, given an str[ ], would return the end of the prefix expression that begins at the first position of str[ ].

Then, str[ ] would consist of a valid prefix expression if the value returned by endPrefix( ) was the same as the end of the string. I.e.

end = strlen( str ) – 1;endPrefix( str, 0, end ) = = end

Page 36: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

36

Recognizer for Prefix Expressions

int endPrefix( char str[ ], int first, int last ){ if( first < 0 | | first > last ) return –1;

if( isLetter( str[ first ] ) ) return first;

if( isOperator( str[ first ] ) ) { int firstEnd = endPrefix( str, first + 1, last ); if( firstEnd > –1 ) return endPrefix( str, firstEnd + 1, last ); return –1; } return –1;}

Page 37: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

37

Translating Prefix Expressions into Postfix

Recall:

<prefixExpr> = <identifier> |

<operator> <prefixExpr> <prefixExpr>

Example: + a * b c

<postfixExpr> = <identifier> |

< postfixExpr> < postfixExpr> <operator>

Example: a b c * +

Page 38: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

38

Translating Prefix into Postfix (Cont’d.)

Therefore, translating prefix into postfix requires translating

<operator> <prefixExpr1> <prefixExpr2>

into

<prefixExpr1> <prefixExpr2> <operator>

then

<prefixExpr1> into < postfixExpr1>

and

<prefixExpr2> into < postfixExpr2>

Page 39: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

39

Translating Prefix to Postfix: Example

preToPost( “ + / a b – c d ” ) = =

preToPost( “ / a b ” ) preToPost( “ – c d ” ) “+” = =

preToPost( “a” ) preToPost( “b” ) “/”preToPost( “c” ) preToPost( “d” ) “–” “+” = =

“a” “b” “/” “c” “d” “–” ‘+” = =

“ a b / c d – + ”

Page 40: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

40

Strategy for a Prefix to Postfix Translator

Let’s define a function

char *preToPost( char prefixExpr[ ], char postfixExpr[ ] )

that, given a prefix expression in prefixExpr[ ], stores the corresponding postfix expression in postfixExpr[ ]. (We will find it useful to return a pointer to the end of the prefix expression that begins at prefixExpr[0]. )

Now, a valid prefix expression can be translated into postfix as follows:

char *postfixExpr = ‘\0’;preToPost( prefixExpr, postfixExpr );

Page 41: 1 Applications of Recursion (Walls & Mirrors - Chapter 5)

41

Prefix to Postfix Translator

char *preToPost( char prefixExpr[ ], char postfixExpr[ ] )

{

if( isLetter( prefixExpr[0] ) )

{ strncat( postfixExpr, prefixExpr, 1 );

return prefixExpr;

} // else prefixExpr[0] is an Operator

char *pend = preToPost( &prefixExpr[1], postfixExpr );

pend = preToPost( pend + 1, postfixExpr );

strncat( postfixExpr, prefixExpr, 1 );

return pend;

}