Syllabus Labs   Homework   Quizzes Notes Scores   Blank

Lecture Notes
Dr. Tong Yu, Jan. 2013
 1. Basic Concepts 2. The Standard Library Container Class 3. Vectors and Component Reuse 4. Lists: A Dynamic Data Structure 5. Stacks and Queues

 6. Sets and Multisets 7. Trees 8. Tree Applications 9. Hashing
```
The history of free man is never written by chance
but by choice -- their choice.
Dwight D. Eisenhower

```

Stacks and Queues

1. Stacks

 a finite list with zero or more elements LIFO insert, delete all take place at head push, pop S = ( a0, a1, .... ,an-1 ) a0 -- bottom element ai is on top of ai-1 an-1 -- top element e.g. ( A, B, C, D, E ) Adaptors     do not directly hold data values but built on top of other containers. stack  > s1;     //need space between > > stack  > s2; stack s3; default is deque stack s4; is same as stack  > s4; stack s5;     //invalid

2. An application example -- postfix arithmetic

infix arithmetic

operator is always between 2 numbers ( operands ) ( 2 + ( 3 * 6 ) ) need to locate the innermost bracket ( know the precedence of the operators ), not easy to find the innermost brackets

postfix arithmetic

operator follows operands
infix postfix
7 - 2 7, 2, -
7 - 2 * 3 7, 2, 3, *, -
4 * 2 - 7 4, 2, *, 7, -
( 3 + 4 / 2 ) * ( 5 * 3 - 6 ) - 8 3, 4, 2, /, +, 5, 3, *, 6, -, *, 8, -

Evaluate a postfix expression

3. need two stacks
• postfix stack stores all tokens ( numbers and operators )
• evaluation stack stores numbers for evaluation

4. retrieve and delete top element from postfix stack

5. if obtain a number, save it in evaluation stack

6. if obtain an operator, get two numbers from evaluation stack:
• perform operation
• save result in evaluation stack

7. repeat until postfix stack is empty
8. e.g. 13, 4, -, 2, 3, *, +
postfix
stack
evaluation
stack
13
4
-
2
3
*
+
___

___
post

eval

4
-
2
3
*
+
___
13
___
post

eval

-
2
3
*4
+
___
13
___
post

eval

2
3
*
+
___
9
___
post

eval

2
3
*
+
___
9
___
post

eval

3
*2
+
___
9
___
post

eval

3
*2
+
___
9
___
post

eval

6
+
___
9
___
post

eval

6
+
___
9
___
post

eval

___
15
___

9. Queues

FIFO ( first in first out )

insertions at one end -- rear ( tail )

deletions at another end -- front ( head )

Q = ( a0, a1, .... ,an-1 )

a0 -- front element
ai+1 is behind ai
an-1 -- rear element

Array

use two cursors to locate front and rear positions
wrap-around

Circular Queue

maxLength = Nmax, currently N items

head ( front ) at N - 1, tail ( rear ) at 0

10. Infix to Postfix conversion

How to convert from infix to postfix?

Observations:

A - B * C + D * E - A / C
11. Fully parenthesize the expression

( ( ( A - ( B * C ) ) + ( D * E ) ) - ( A / C ) )

12. Observe that each operator associates with one right parenthesis:

( ( ( A- ( B * C ) ) + ( D * E ) ) - ( A / C ) )

13. But

( B * C ) is translated to B C *

14. So we move all operators so that they replace their corresponding right parenthesis

( ( ( A   B   C * - ( D   E * + ( A   C / -

15. Then delete all parenthesis

A   B   C   *   -   D   E   *   +   A   C   /   -

which is the required postfix expression

16. Observe: order of operands ( numbers ) are the same as in prefix and postfix expressions
17. Since orders of operands of infix and postfix are the same, we can scan the infix expression and form postfix expression by parsing the operands and use a queue to hold them
on the other hand we can use an stack to hold the operators

e.g. A + B * C

infix
stack
operator
stack
postfix
queue
A
+
B
*
C
__

__

infix

oper

postfix

+
B
*
C
__

__

A

infix

oper

postfix

B
*
C
__

+
__

A

infix

oper

postfix

*
C
__

+
__

B
A

infix

oper

postfix

C
__

*
+
__

B
A

* has higher precedence
thus at higher position
in stack
infix

oper

postfix

__

*
+
__

C
B
A

infix

oper

postfix

__

__
+
*
C
B
A

So the postfix expression is :
A B C * +

e.g. A /( B + C ) * D

 A/(B+C)*D__ __

 (B+C)*D__ /__ A

 B+C)*D__ (/__ A

 +C)*D__ (/__ BA

 C)*D__ +(/__ BA
 )*D__ +(/__ CBA

 )*D__ +(/__ CBA the ) associated with '+' has higher precedence, thus transfer

 *D__ /__ +CBA

 *D__ /__ +CBA '*' and '/' have same precedence, but '/' occurs first. thus transfer '/'

 D__ *__ / +CBA
 __ *__ D/ +CBA

 __ __ *D/ +CBA
Infix stack empty.
So done!
postfix: A B C + / D *

Implementations

 ```//token.h #ifndef TOKEN_H #define TOKEN_H #include #include #include #include #include typedef double dataType; //could be int or double enum whatKind { operate, number }; class TOKEN { public: whatKind kind; dataType num; char op; }; void in2post ( stack &infix, queue &postq ); dataType evaluate ( queue &post ); #endif ```

 ```//util.h #ifndef UTIL_H #define UTIL_H void q2stack( queue &q, stack &s ); void reverse_stack( stack &s, stack &sr ); bool c_is_an_operator( char c ); void print_queue( queue q ); void print_stack( stack s ); #endif ```

 ```//in2postd.cpp #include "token.h" int precedence ( char c ) { switch ( c ) { case '+': case '-': return 1; case '*': case '/': return 2; } return 0; //lowest } void transfer ( stack &s, queue &q ) { q.push( s.top() ); s.pop(); //remove top element of stack } void in2post ( stack &infix, queue &postq ) { stack opstack; //operator stack TOKEN a; while ( !infix.empty() ) { a = infix.top(); //get a Token from infix stack infix.pop(); //remove token at top if ( a.kind == number ) postq.push( a ); //enter a to postfix queue else if ( opstack.empty() ) opstack.push( a ); //put token in operator stack else if ( a.op == '(' ) //'(' has lowest precedence, always put it in op stack opstack.push( a ); else if ( a.op == ')' ){ //encounters right parenthesis, so transfer everything enclosed by ( .. ) while ( opstack.top().op != '(' ) transfer ( opstack, postq ); opstack.pop(); //remove '(' after the transfer } else { while ( !opstack.empty() && precedence( a.op ) <= precedence( opstack.top().op ) ) transfer ( opstack, postq ); opstack.push( a ); } } //while while ( !opstack.empty() ) transfer ( opstack, postq ); } ```

 ```//evaluate.cpp #include "token.h" //evaluates postfix expression represented as a queue of tokens //assumes that postfix expression is correctly formed dataType evaluate ( queue &post ) { stack eval; dataType first, second, ans; char bin_op; TOKEN tp, te; while ( !post.empty() ) { tp = post.front(); post.pop(); if ( tp.kind == number ) //number eval.push( tp ); //save the number on evaluation stack else { //its an operator te = eval.top(); //get a 'number' from eval stack first = te.num; eval.pop(); te = eval.top(); //get a second 'number' second = te.num; eval.pop(); bin_op = tp.op; switch ( bin_op ) { case '+' : ans = second + first; break; case '-' : ans = second - first; break; case '*' : ans = second * first; break; case '/' : ans = second / first; break; } //switch te.num = ans; //save the result eval.push ( te ); } //else } //while te = eval.top(); return te.num; } ```

18. Back tracking

Solving a problem by trial and error in a well organized manner:
19. never try the same thing twice,
20. if the problem is finite we will eventually try all possibilities
21. if the steps tried do not lead to a solution, some or all of them may
have to be retraced and the relevant details discarded
22. e.g. nonattacking queens

Try this.
 Q Q Q Q Q Q Q Q

Brute force

 648 = 4,426,165,368

Only one queen in each row

88 = 16,777,216

Rejects position whose column or diagonals are guarded

8! = 40, 320

To solve the problem, when we place a queen on a square, we check if is under attack; if no, proceed; if yes, remove the queen and back track

r1
row
r2
 0 1 2 3 0 1 2 3 4

 ```//queen8.cpp #include class queen8 { public: queen8(); void clearBoard(); void displayBoard(); void placeQueen( int col, bool &done ); private: enum square{QUEEN, EMPTY}; square board[8][8]; void setQueen( int row, int col ); //set to square( row, col) to QUEEN void removeQueen( int row, int col ); //set to EMPTY bool isUnderAttack( int row, int col ); //determines whether ( row, col ) is under attack by any // queens 1 through col-1 // int index( int n ); }; queen8::queen8() { int i, j; for ( i = 0; i < 8; ++i ) for( j = 0; j < 8; ++j ) board[i][j] = EMPTY; } void queen8::placeQueen( int col, bool & done ) { if ( col > 7 ) done = true; else { done = false; int row = 0; while ( !done && ( row < 8 ) ) { if ( isUnderAttack( row, col ) ) ++row; else { //place queen and consider next column setQueen( row, col ); placeQueen( col+1, done ); if ( !done ) { //if no queen is possible in next col //backtrack removeQueen( row, col ); ++row; } } //else }//while } //else } //queen8 void queen8::setQueen( int row, int col ) { board[row][col] = QUEEN; } void queen8::removeQueen( int row, int col ) { board[row][col] = EMPTY; } bool queen8::isUnderAttack( int row, int col ) //precondition : each column between 0 and col-1 //has a queen placed in it { int r1, r2, c; r1 = row-1; r2 = row+1; for ( c = col-1; c >= 0 ; --c ) { if ( board[row][c] == QUEEN ) return true; if ( r1 >= 0 ) { if ( board[r1][c] == QUEEN ) return true; --r1; } if ( r2 < 8 ) { if ( board[r2][c] == QUEEN ) return true; ++r2; } } //for return false; } void queen8::displayBoard() { int row, col; cout << endl; for ( row = 0; row < 8; ++row ) { for ( col = 0; col < 8; ++col ) { if ( board[row][col] == QUEEN ) cout << "Q "; else cout << "X "; } cout << endl; } } void main() { queen8 q8; bool done = false; q8.placeQueen( 0, done ); q8.displayBoard(); } ```

23. Deques: Double-Ended Queues

An interesting and versatile data structure in STL:
24. a combination of stack and queue
25. allow elements to be inserted and removed at both ends (fast)
26. like vector, insertion at middle allowed but not efficient ( O(n) )
27. STL deque operations are a combination of vector and list
28. Application: Depth- and Breadth- Search

Consider a maze:
29. can be divided into cells (squares)
30. find a path using a deque to save neigbors
31. Depth-first search: push_front()
```        front         back
20
19 15
22 18 15
16 17 18 15
```
32. Breadth-first search: push_back()
```        front                back
20
15 19
15 10 14
17 21  2  8 8 12
```
33. each cell is characterized by its 'walls', specified by a 4-bit
binary number denoting W, N, E, S.

 Decimal W N E S Walls 0 0 0 0 0 1 0 0 0 1 2 0 0 1 0 | 3 0 0 1 1 | . . . 7 0 1 1 1 . . . . . . 10 1 0 1 0 |     | . . . . . . 15 1 1 1 1
34. A class cell should have
1. An id number identifying the cell
2. A list maintaining neigbouring cells
3. A boolean value indicating whether the cell has been visited
```class cell {
protected:
int id;
bool visited;
list <cell *> neighbors;
public:
//constructor
cell ( int n )
{
id = n;
visited = false;
}

void addNeighbor ( cell *a )
{
neighbors.push_back ( a );
}
bool visit ( deque <cell *> & );
};
```
35. Class maze maintains the entire maze structure; should have
1. a pointer to the starting cell
2. a boolean flag indicating the destination has been reached
3. a deque to remember the traversed paths
```class maze {
protected:
cell *start;
bool finished;
deque <cell *> path;
public:
maze ( istream & );
void solveMaze();
};
```