CSCS-200 Data Structure and Algorithms. Lecture

CSCS-200 Data Structure and Algorithms Lecture 10-11-12 THE STACK What is a stack?  It is an ordered group of homogeneous items of elements.  El...
Author: Andrew Foster
3 downloads 0 Views 1MB Size
CSCS-200 Data Structure and Algorithms Lecture 10-11-12

THE STACK

What is a stack?  It is an ordered group of homogeneous items of elements.  Elements are added to and removed from the top of the stack (the most

recently added items are at the top of the stack).  The last element to be added is the first to be removed (LIFO: Last In, First Out).

Stacks  Stacks in real life: stack of books, stack of plates  Add new items at the top  Remove an item at the top  Stack data structure similar to real life: collection of

elements arranged in a linear order.  Can only access element at the top

4

AL

Stack Specification  Definitions: (provided by the user)  MAX_ITEMS: Max number of items that might be on the stack  ItemType: Data type of the items on the stack  Operations  MakeEmpty  Boolean IsEmpty  Boolean IsFull  Push (ItemType newItem)  Pop (ItemType& item)

Stack Operations  Push(X) – insert X as the top element of the stack  Pop() – remove the top element of the stack and

return it.  Top() – return the top element without removing it from the stack.

6

AL

Push (ItemType newItem)  Function: Adds newItem to the top of the stack.

 Preconditions: Stack has been initialized and is

not full.  Postconditions: newItem is at the top of the stack.

Pop (ItemType& item)  Function: Removes topItem from stack and returns it in item.  Preconditions: Stack has been initialized and is not empty.  Postconditions: Top element has been removed from stack and

item is a copy of the removed element.

Stack Operations top top 5

7 5

7 5

2

2

2

2

push(2)

push(5)

push(7)

push(1)

top top

top top

1 9

21

7 5

7 5

2

2

pop()

1

push(21)

top

7 5

top

5

2 21

pop()

2 7

pop()

top

2 5

pop() AL

Stack Operation  The last element to go into the stack is the first to

come out: LIFO – Last In First Out.  What happens if we call pop() and there is no element?  Have IsEmpty() boolean function that returns true if stack is empty, false otherwise.  Throw StackEmpty exception: advanced C++/JAVA concept.

10

AL

Stack Implementation: Array  Worst case for insertion and deletion from an array

when insert and delete from the beginning: shift elements to the left.  Best case for insert and delete is at the end of the array – no need to shift any elements.  Implement push() and pop() by inserting and deleting at the end of an array.

11

AL

Stack using an Array

top

1 7 5 2

12

2

5

7

1

0

1

2

3

4

top = 3

AL

Stack using an Array  In case of an array, it is possible that the array may

“fill-up” if we push enough elements.  Have a boolean function IsFull() which returns true if stack (array) is full, false otherwise.  We would call this function before calling push(x).

13

AL

Stack Operations with Array public int pop() { return A[current--]; } public void push(int x) { A[++current] = x; } 14

AL

Stack Operations with Array public int { return } public int { return } public int { return }

top()

A[current]; IsEmpty() ( current == -1 );

IsFull() ( current == size-1);

 A quick examination shows that all five operations

take constant time.

15

AL

Use of Stack  Example of use: prefix, infix, postfix expressions.  Consider the expression A+B: we think of applying

the operator “+” to the operands A and B.  “+” is termed a binary operator: it takes two operands.  Writing the sum as A+B is called the infix form of the expression.

16

Prefix, Infix, Postfix  Two other ways of writing the expression are

+ A B prefix A B + postfix  The prefixes “pre” and “post” refer to the position of

the operator with respect to the two operands.

17

Prefix, Infix, Postfix  Consider the infix expression

A+B*C  We “know” that multiplication is done before addition.  The expression is interpreted as A+(B*C)  Multiplication has precedence over addition.

18

Prefix, Infix, Postfix  Conversion to postfix

A+(B*C)

19

infix form

Prefix, Infix, Postfix  Conversion to postfix

A+(B*C) A+(BC*)

20

infix form convert multiplication

Prefix, Infix, Postfix  Conversion to postfix

A+(B*C) A+(BC*) A(BC*)+

21

infix form convert multiplication convert addition

Prefix, Infix, Postfix  Conversion to postfix

A+(B*C) A+(BC*) A(BC*)+ ABC*+

22

infix form convert multiplication convert addition postfix form

Prefix, Infix, Postfix  Conversion to postfix

(A + B ) * C

23

infix form

Prefix, Infix, Postfix  Conversion to postfix

(A + B ) * C (AB+)*C

24

infix form convert addition

Prefix, Infix, Postfix  Conversion to postfix

(A + B ) * C (AB+)*C (AB+)C*

25

infix form convert addition convert multiplication

Prefix, Infix, Postfix  Conversion to postfix

(A + B ) * C (AB+)*C (AB+)C* AB+C*

26

infix form convert addition convert multiplication postfix form

Precedence of Operators  The five binary operators are: addition, subtraction,    

27

multiplication, division and exponentiation. The order of precedence is (highest to lowest) Exponentiation  Multiplication/division *, / Addition/subtraction +, -

Precedence of Operators  For operators of same precedence, the left-to-right

rule applies: A+B+C means (A+B)+C.  For exponentiation, the right-to-left rule applies

A  B  C means A  ( B  C )

28

Infix to Postfix Infix A+B 12 + 60 – 23 (A + B)*(C – D ) A  B * C – D + E/F

29

Postfix AB+ 12 60 + 23 – AB+CD–* A B  C*D – E F/+

Infix to Postfix  Note that the postfix form an expression does not

require parenthesis.  Consider „4+3*5‟ and „(4+3)*5‟. The parenthesis are not needed in the first but they are necessary in the second.  The postfix forms are: 4+3*5 435*+ (4+3)*5 43+5*

30

Evaluating Postfix  Each operator in a postfix expression refers to the

previous two operands.  Each time we read an operand, we push it on a stack.  When we reach an operator, we pop the two operands from the top of the stack, apply the operator and push the result back on the stack.

31

Evaluating Postfix Stack s; while( not end of input ) { e = get next element of input if( e is an operand ) s.push( e ); else { op2 = s.pop(); op1 = s.pop(); value = result of applying operator „e‟ to op1 and op2; s.push( value ); } } finalresult = s.pop(); 32

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

6

33

op1

op2

value

stack

6

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

34

op1

op2

value

stack

6

6

2

6,2

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

35

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

op2

value

stack

6

6

2

6,2

3

6,2,3

+

36

op1

2

3

5

6,5

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

37

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

38

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

39

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

40

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

2

6

5

1

1,3,8,2

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

41

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

2

6

5

1

1,3,8,2

/

8

2

4

1,3,4

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

42

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

2

6

5

1

1,3,8,2

/

8

2

4

1,3,4

+

3

4

7

1,7

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

43

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

2

6

5

1

1,3,8,2

/

8

2

4

1,3,4

+

3

4

7

1,7

*

1

7

7

7

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input

44

op1

op2

value

stack

6

6

2

6,2

3

6,2,3

+

2

3

5

6,5

-

6

5

1

1

3

6

5

1

1,3

8

6

5

1

1,3,8

2

6

5

1

1,3,8,2

/

8

2

4

1,3,4

+

3

4

7

1,7

*

1

7

7

7

2

1

7

7

7,2

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input 6 2 3 + 3 8 2 / + * 2  45

op1

op2

value

2 6 6 6 6 8 3 1 1 7

3 5 5 5 5 2 4 7 7 2

5 1 1 1 1 4 7 7 7 49

stack 6 6,2 6,2,3 6,5 1 1,3 1,3,8 1,3,8,2 1,3,4 1,7 7 7,2 49

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 +

46

Input 6 2 3 + 3 8 2 / + * 2  3

op1

op2

value

2 6 6 6 6 8 3 1 1 7 7

3 5 5 5 5 2 4 7 7 2 2

5 1 1 1 1 4 7 7 7 49 49

stack 6 6,2 6,2,3 6,5 1 1,3 1,3,8 1,3,8,2 1,3,4 1,7 7 7,2 49 49,3

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input 6 2 3 + 3 8 2 / + * 2  3 47 +

op1

op2

value

2 6 6 6 6 8 3 1 1 7 7 49

3 5 5 5 5 2 4 7 7 2 2 3

5 1 1 1 1 4 7 7 7 49 49 52

stack 6 6,2 6,2,3 6,5 1 1,3 1,3,8 1,3,8,2 1,3,4 1,7 7 7,2 49 49,3 52

Evaluating Postfix Evaluate 6 2 3 + - 3 8 2 / + * 2  3 + Input 6 2 3 + 3 8 2 / + * 2  3 48 +

op1

op2

value

2 6 6 6 6 8 3 1 1 7 7 49

3 5 5 5 5 2 4 7 7 2 2 3

5 1 1 1 1 4 7 7 7 49 49 52

stack 6 6,2 6,2,3 6,5 1 1,3 1,3,8 1,3,8,2 1,3,4 1,7 7 7,2 49 49,3 52

Converting Infix to Postfix  Consider the infix expressions „A+B*C‟ and „

(A+B)*C‟.  The postfix versions are „ABC*+‟ and „AB+C*‟.  The order of operands in postfix is the same as the infix.  In scanning from left to right, the operand „A‟ can be inserted into postfix expression.

49

Converting Infix to Postfix  The „+‟ cannot be inserted until its second operand

has been scanned and inserted.  The „+‟ has to be stored away until its proper position is found.  When „B‟ is seen, it is immediately inserted into the postfix expression.  Can the „+‟ be inserted now? In the case of „A+B*C‟ cannot because * has precedence.

50

Converting Infix to Postfix  In case of „(A+B)*C‟, the closing parenthesis

indicates that „+‟ must be performed first.  Assume the existence of a function „prcd(op1,op2)‟ where op1 and op2 are two operators.  Prcd(op1,op2) returns TRUE if op1 has precedence over op2, FASLE otherwise.

51

Converting Infix to Postfix  prcd(„*‟,‟+‟) is TRUE  prcd(„+‟,‟+‟) is TRUE  prcd(„+‟,‟*‟) is FALSE  Here is the algorithm that converts infix expression

to its postfix form.  The infix expression is without parenthesis.

52

Converting Infix to Postfix 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

13. 14. 15. 53

16.

Stack s; While( not end of input ) { c = next input character; if( c is an operand ) add c to postfix string; else { while( !s.empty() && prcd(s.top(),c) ){ op = s.pop(); add op to the postfix string; } s.push( c ); } while( !s.empty() ) { op = s.pop(); add op to postfix string; }

Converting Infix to Postfix  Example: A + B * C

symb A

54

postfix A

stack

Converting Infix to Postfix  Example: A + B * C

symb A +

55

postfix A A

stack +

Converting Infix to Postfix  Example: A + B * C

symb A + B

56

postfix A A AB

stack + +

Converting Infix to Postfix  Example: A + B * C

symb A + B *

57

postfix A A AB AB

stack + + +*

Converting Infix to Postfix  Example: A + B * C

symb A + B * C

58

postfix A A AB AB ABC

stack + + +* +*

Converting Infix to Postfix  Example: A + B * C

symb A + B * C

59

postfix A A AB AB ABC ABC *

stack + + +* +* +

Converting Infix to Postfix  Example: A + B * C

symb A + B * C

60

postfix A A AB AB ABC ABC * ABC * +

stack + + +* +* +

Converting Infix to Postfix  Handling parenthesis  When an open parenthesis „(„ is read, it must be

pushed on the stack.  This can be done by setting prcd(op,„(„ ) to be FALSE.  Also, prcd( „(„,op ) == FALSE which ensures that an operator after „(„ is pushed on the stack.

61

Converting Infix to Postfix  When a „)‟ is read, all operators up to the first „(„ must

be popped and placed in the postfix string.  To do this, prcd( op,‟)‟ ) == TRUE.  Both the „(„ and the „)‟ must be discarded: prcd( „(„,‟)‟ ) == FALSE.  Need to change line 11 of the algorithm.

62

Converting Infix to Postfix if( s.empty() || symb != „)‟ ) s.push( c ); else s.pop(); // discard the „(„ prcd( „(„, op ) = FALSE for any operator prcd( op, „)‟ ) = FALSE for any operator other than „)‟ prcd( op, „)‟ ) = TRUE for any operator other than „(„ prcd( „)‟, op ) = error for any operator. 63

Lab Exercise Create a stack of integers with ten elements. Program should output as follows: Print the elements of the stack. Remove 5 elements from the stack. Print the elements of stack again. Insert 2 more elements. Print the elements of stack. Increase each element by 1 and print again.

What is a queue?

 It is an ordered group of homogeneous items of elements.  Queues have two ends:  Elements are added at one end.  Elements are removed from the other end.  The element added first is also removed first (FIFO: First In,

First Out).

Queue  Initially q.rear = -1  When is queue empty?  Q.rear < q.front

 Total Number of Elements = q.rear –q.front + 1

An Implementation Problem  Consider a 5 element queue  Initially q.front = 0 and q.rear = -1  After Inserting 3 elements delete two elements and again

insert two elements.  Can you insert any more?

One Solution  After one removal move all elements one step up and fix

front = 0.  In this case no front variable is needed.  But not an efficient solution. Why?

Queue Specification  Definitions: (provided by the user)  MAX_ITEMS: Max number of items that might be on the queue  ItemType: Data type of the items on the queue



Operations     

MakeEmpty Boolean IsEmpty Boolean IsFull Enqueue (ItemType newItem) Dequeue (ItemType& item)

Enqueue (ItemType newItem)  Function: Adds newItem to the rear of the queue.  Preconditions: Queue has been initialized and is not full.  Postconditions: newItem is at rear of queue.

Dequeue (ItemType& item)  Function: Removes front item from queue and returns it in

item.  Preconditions: Queue has been initialized and is not empty.  Postconditions: Front element has been removed from queue and item is a copy of removed element.

Implementation issues  Implement the queue as a circular structure.  How do we know if a queue is full or empty?

 Initialization of front and rear.  Testing for a full or empty queue.

Queue using Array  If we use an array to hold queue elements, both

insertions and removal at the front (start) of the array are expensive.  This is because we may have to shift up to “n” elements.  For the stack, we needed only one end; for queue we need both.  To get around this, we will not shift upon removal of an element.

73

Queue using Array

front

rear 1

1 7

5

5

2

2

3

2 0

74

7 1

4

front

rear

0

3

5

6

7

Queue using Array enqueue(6)

front

rear 1

1 7

5

5

2

6

2

3

4

2 6 0

75

7 1 front

rear

0

4

5

6

7

Queue using Array enqueue(8)

front

rear 1

1

7

5

2

6

5

2

6

8

2

3

4

5

8 0

76

7 1 front

rear

0

5

6

7

Queue using Array dequeue()

front

rear 7

7

5

2

6

2

6

8

2

3

4

5

8 0

77

5

1 front

rear

1

5

6

7

Queue using Array dequeue()

front 5

rear 2

6

2

6

8

2

3

4

5

8 0

78

5 1 front

rear

2

5

6

7

Queue using Array enqueue(9) enqueue(12)

front 5

rear 2

6

8

79

2

6

8

9

12

2

3

4

5

6

7

9 12 0

enqueue(21) ??

5 1 front

rear

2

7

Queue using Array  We have inserts and removal running in constant

time but we created a new problem.  Cannot insert new elements even though there are two places available at the start of the array.  Solution: allow the queue to “wrap around”.

80

Queue using Array  Basic idea is to picture the array as a circular array.

0 front 5

rear 2

6

8

front

7

9 12 6

12

5

9

2 8 5

81

1

6 4

2

2

3

rear 7

Queue using Array enqueue(21) 0 front 5

rear 2

6

8

7

9 12 21 6

1

21 12

5

9

2 8

6

5

public void enqueue(int x) { rear = (rear+1)%size; array[rear] = x; noElements = noElements+1; } 82

4

front

size

2

2

8

3

rear 0

noElements 7

Queue using Array enqueue(7) 0 front 5

rear 2

6

8

7

9 12 21 7 6

1

21

7

12

5

9

2 8 5

6

public int isFull() { return noElements == size; }

83

public int isEmpty() { return noElements == 0; }

4

front

size

2

2

8

3

rear 1

noElements 8

Queue using Array dequeue() 0 front 6

rear 8

7

9 12 21 7 6

1

21 12 9 8 5

public int dequeue() { int x = array[front]; front = (front+1)%size; noElements = noElements-1; return x; } 84

7

6 4

front

size

2

4

8

3

rear

1

noElements 6

Use of Queues  Out of the numerous uses of the queues, one of the

most useful is simulation.  A simulation program attempts to model a real-world phenomenon.  Many popular video games are simulations, e.g., SimCity, FlightSimulator  Each object and action in the simulation has a counterpart in real world.

85

Uses of Queues  If the simulation is accurate, the result of the

program should mirror the results of the real-world event.  Thus it is possible to understand what occurs in the real-world without actually observing its occurrence.  Let us look at an example. Suppose there is a bank with four tellers.

86

Stack Using Linked List  We can avoid the size limitation of a stack

implemented with an array by using a linked list to hold the stack elements.  As with array, however, we need to decide where to insert elements in the list and where to delete them so that push and pop will run the fastest.

Stack Using Linked List  For a singly-linked list, insert at start or end takes

constant time using the head and current pointers respectively.  Removing an element at the start is constant time but removal at the end required traversing the list to the node one before the last.  Make sense to place stack elements at the start of the list because insert and removal are constant time.

Stack Using Linked List  No need for the current pointer; head is enough.

head top

1 7 5 2

1

7

5

2

Stack Operation: List public int pop() { int x = head.get(); ListNode p = head; head = head.getNext(); return x; }

head top

7 5 2

1

7

5

2

Stack Operation: List public void push(int x) { ListNode newNode = new Node(); newNode.set(x); newNode.setNext(head); head = newNode; } head top

9

7 5 2

7 newNode

push(9)

9

5

2

Stack Operation: List public int { return } public int { return }

top()

head->get(); IsEmpty() ( head == NULL );

• All four operations take constant time.

We implement IsFull() function only in array implementation because we expect enough memory will be available.

Stack: Array or List • Since both implementations support stack

• •





operations in constant time, any reason to choose one over the other? Allocating and deallocating memory for list nodes does take more time than preallocated array. List uses only as much memory as required by the nodes; array requires allocation ahead of time. List pointers (head, next) require extra memory. Array has an upper limit; List is limited by dynamic memory allocation.

Implementing Queue  Using linked List: Recall  Insert works in constant time for either end of a

linked list.  Remove works in constant time only.  Seems best that head of the linked list be the front of the queue so that all removes will be from the front.  Inserts will be at the end of the list.

Implementing Queue  Using linked List:

front 1 7

rear 5

2

rear

front 1

7

5

2

Implementing Queue  Using linked List:

front

rear

1 7

5

2

rear

front 1

7

5

2

dequeue() front

7

rear

5

2

rear

front

1

7

5

2

Implementing Queue  Using linked List:

front 1 7

5

rear

front

rear

1

2

7

5

2

enqueue(9) front

7

rear

5

2

9

rear

front

7

5

2

9

Implementing Queue public int dequeue() { int x = front.get(); ListNode p = front; front = front.getNext(); return x; } public void enqueue(int x) { ListNode newNode = new ListNode(); newNode.set(x); newNode.setNext(NULL); rear.setNext(newNode); rear = newNode; }

Implementing Queue public int front() { return front->get(); }

public int isEmpty() { return ( front == NULL ); }

Simulation of a Bank  A customer enters the bank at a specific time (t1)

desiring to conduct a transaction.  Any one of the four tellers can attend to the customer.  The transaction (withdraw, deposit) will take a certain period of time (t2).  If a teller is free, the teller can process the customer‟s transaction immediately and the customer leaves the bank at t1+t2.

Simulation of a Bank  A customer enters the bank at a specific time (t1)

desiring to conduct a transaction.  Any one of the four tellers can attend to the customer.  The transaction (withdraw, deposit) will take a certain period of time (t2).  If a teller is free, the teller can process the customer‟s transaction immediately and the customer leaves the bank at t1+t2.

Simulation of a Bank  It is possible that none of the four tellers is free in

which case there is a line of customers are each teller.  An arriving customer proceeds to the back of the shortest line and waits for his turn.  The customer leaves the bank at t2 time units after reaching the front of the line.  The time spent at the bank is t2 plus time waiting in line.

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation of a Bank teller 1

teller 2

teller 3

teller 4

Simulation Models  Two common models of simulation are time-based

simulation and event-based simulation.  In time-based simulation, we maintain a timeline or a clock.  The clock ticks. Things happen when the time reaches the moment of an event.

Timeline based Simulation  Consider the bank example. All tellers are free.

 Customer C1 comes in at time 2 minutes after

bank opens.  His transaction (withdraw money) will require 4 minutes.  Customer C2 arrives 4 minutes after the bank opens. Will need 6 minutes for transaction.  Customer C3 arrives 12 minutes after the bank opens and needs 10 minutes.

Timeline based Simulation  Events along the timeline:

Time (minutes) 0

1

2

3

4

C1 in

5

6

7

8

10

11

12

C1 out C2 in

C2 out C3 in

13

14

15

Timeline based Simulation  We could write a main clock loop as follows: clock = 0; while( clock