You are on page 1of 90

Stacks

Briana B. Morrison
Adapted from Alan Eugenio

Topics

Define Stack
APIs
Applications

Create Hex Number


Recursion
Converting from Infix to Postfix
Evaluating Postfix
Converting from Infix to Prefix

Implementation

Array based
Linked list based
Stacks

Stacks

A stack is a sequence of items that are


accessible at only one end of the sequence.

Stacks

Pushing/Popping a Stack
Because

a pop removes the item last added to


the stack, we say that a stack has LIFO (lastin/first-out) ordering.

Stacks

TOP THE MOST RECENTLY INSERTED


ITEM
PUSH - TO INSERT ONTO THE TOP OF A
STACK
POP - TO REMOVE THE TOP ITEM IN A
STACK
Stacks

THE stack CLASS IS TEMPLATED:


template <class T, class Container = deque<T> >

T IS THE TEMPLATE PARAMETER


FOR THE ITEM TYPE. Container IS THE
TEMPLATE PARAMETER FOR THE
CLASS THAT WILL HOLD THE ITEMS.

Stacks

METHOD INTERFACES
FOR THE
stack CLASS

Stacks

CLASS stack

Constructor

<stack>

Operations

<stack>

stack();
Create an empty stack
CLASS stack

bool empty(); const


Check whether the stack is empty. Return true if it is
empty and false otherwise.

Stacks

CLASS stack

Operations

<stack>

void pop();
Remove the item from the top of the stack.
Precondition:
The stack is not empty.
Postcondition: Either the stack is empty or
the stack has a new topmost
item from a previous push.
void push(const T& item);
Insert the argument item at the top of the stack.
Postcondition: The stack has a new item at
the top.

Stacks

CLASS stack

Operations

<stack>

int size() const;


Return the number of items on the stack.
T& top() const;
Return a reference to the value of the item at the
top of the stack.
Precondition: The stack is not empty.
const T& top() const;
Constant version of top().

Stacks

10

THERE ARE NO ITERATORS!

THE ONLY ACCESSIBLE ITEM IS THE


FRONT ITEM.

Stacks

11

DETERMINE THE OUTPUT FROM


THE FOLLOWING:
stack<int> my_stack;
for (int i = 0; i < 10; i++)
my_stack.push (i * i);
while (!my_stack.empty())
{
cout << my_stack.top() << endl;
my_stack.pop();
} // while
Stacks

12

LIKE THE queue CLASS, THE stack


CLASS IS A CONTAINER ADAPTER.
THE UNDERLYING CLASS MUST HAVE
empty, size, push_back, pop_back, AND
back METHODS.

Stacks

13

Implementing stack an adapter


of vector

The standard library implements the stack as


an adapter of any sequential container.
The member functions are delegated to the
member functions of the container.
Any of the three sequential containers can be
used: vector, list, or deque.
The standard library uses the deque by
default.
We will use the vector, and describe the
deque in the next chapter.
Stacks

14

SO THE vector, deque, AND list CLASSES


CAN SERVE AS THE UNDERLYING
CONTAINER CLASS.
NOTE: THE TOP ITEM ON THE
STACK IS AT THE BACK OF THE
UNDERLYING CONTAINER!

Stacks

15

Implementing Stack as
Extension of Vector

Top element of the


Stack is at the
highest index

Stacks

16

HERE IS PART OF THE DEFINITION OF


THE stack CLASS:
template <class T, class Container = deque<T> >
class stack
{
protected:
Container c;
public:

void push (const value_type& x)


{
c.push_back (x);
}
}
Stacks

17

stack Code
template<typename Item_Type>
void stack<Item_Type>::push(const Item_Type& item) {
container.push_back(item);
}
template<typename Item_Type>
Item_Type& stack<Item_Type>::top() {
return container.back();
}
template<typename Item_Type>
const Item_Type& stack<Item_Type>::top() const {
return container.back();
}
Stacks

18

Stack Code (2)


template<typename Item_Type>
void stack<Item_Type>::pop() {
container.pop_back();
}
template<typename Item_Type>
bool stack<Item_Type>::empty() const {
return container.empty();
}
template<typename Item_Type>
size_t stack<Item_Type>::size() const {
return container.size();
}
Stacks

19

STACK APPLICATIONS

Stacks

20

Applications of Stacks

Direct applications

Page-visited history in a Web browser


Undo sequence in a text editor
Saving local variables when one function calls another, and
this one calls another, and so on.

Indirect applications

Auxiliary data structure for algorithms


Component of other data structures

Stacks

21

Using a Stack to Create a


Hex Number
'1 '
'F '
431 % 16 = 15
431 / 16 = 26

'1 '

'A '

'A '

'A '

'F '

'F '

'F '

26 % 16 = 10
26 / 16 = 1

1 % 16 = 1
1 / 16 = 0

'A '
'F '

P o p '1 '
n u m Str = "1 "

P u s h D ig it C h a r a c t e r s

'F '

P o p 'A '
P o p 'F '
n u m Str = "1 A " n u m Str = "1 A F "

P o p D ig it C h a r a c t e r s

Stacks

22

STACK APPLICATION

HOW COMPILERS IMPLEMENT


RECURSION
Stacks

23

WHENEVER A FUNCTION IS CALLED,


INFORMATION IS SAVED TO
PREVENT OVERLAYING OF THAT
INFO IN CASE THE METHOD IS
RECURSIVE. THIS INFORMATION IS
COLLECTIVELY REFERRED TO AS AN
ACTIVATION RECORD OR STACK
FRAME.
Stacks

24

EACH ACTIVATION RECORD CONTAINS:


1. A VARIABLE THAT CONTAINS THE RETURN ADDRESS
IN THE CALLING METHOD;
2. FOR EACH VALUE FORMAL PARAMETER,
VARIABLE THAT CONTAINS A COPY OF THE
ARGUMENT;

3. FOR EACH REFERENCE FORMAL PARAMETER, A


VARIABLE THAT CONTAINS THE ADDRESS OF THE
ARGUMENT;
4. FOR EACH VARIABLE DEFINED IN THE METHODS
BLOCK, A VARIABLE THAT CONTAINS A COPY OF
THAT DEFINED VARIABLE.
Stacks

25

THERE IS A RUN-TIME STACK TO

HANDLE THESE ACTIVATION


RECORDS.

PUSH: WHEN FUNCTION IS CALLED

POP: WHEN EXECUTION OF


FUNCTION IS COMPLETED
Stacks

26

AN ACTIVATION RECORD IS SIMILAR


TO AN EXECUTION FRAME, EXCEPT
THAT AN ACTIVATION RECORD HAS
VARIABLES ONLY, NO CODE.

YOU CAN REPLACE RECURSION


WITH ITERATION BY CREATING
YOUR OWN STACK.
Stacks

27

C++ Run-time Stack

main() {
The C++ run-time system keeps
int i = 5;
track of the chain of active functions
with a stack
foo(i);
When a function is called, the run}
time system pushes on the stack a
frame containing
foo(int j) {
Local variables and return value
int k;
Program counter, keeping track of
k = j+1;
the statement being executed
bar(k);
When a function returns, its frame is
}
popped from the stack and control
is passed to the method on top of
bar(int m) {
the stack

Stacks

bar
PC = 1
m=6
foo
PC = 3
j=5
k=6
main
PC = 2
i=5
28

A rg u m e n ts
in t n

R e tu rn A d d re ss
R e tL o c o r R e tL o c 2

A c tivatio n R e c o r d
S y s te m S ta ck
I n m a in ( ) :
c a ll f a c t ( 4 )

In fact(4 ):
c a ll f a c t ( 3 )

A rg u m e n t

R e tu rn

R etL o c1

A rg u m e n t

R e tu r n

R etL o c2

A rg u m e n t

R e tu r n

R etL o c1

Stacks

29

Stacks

30

Stacks

31

STACK APPLICATION

CONVERTING FROM
INFIX TO POSTFIX
Stacks

32

IN INFIX NOTATION, AN OPERATOR


IS PLACED BETWEEN ITS
OPERANDS.
a+b
c d + (e * f g * h) / i

Stacks

33

OLD COMPILERS:
INFIX

MACHINE LANGUAGE

THIS GETS MESSY


PARENTHESES.

BECAUSE

OF

NEWER COMPILERS:
INFIX

POSTFIX

Stacks

MACHINE LANG.

34

In POSTFIX Notation, An OPERATOR is


placed IMMEDIATELY AFTER its
OPERANDS.
INFIX

POSTFIX
a

Stacks

35

PARENTHESES ARE NOT NEEDED,


AND NOT USED, IN POSTFIX.

Stacks

36

LETS CONVERT AN INFIX STRING TO


A POSTFIX STRING.
xy*z

Stacks

37

POSTFIX PRESERVES THE ORDER OF


OPERANDS, SO AN OPERAND CAN BE
APPENDED TO POSTFIX AS SOON AS
THAT OPERAND IS ENCOUNTERED IN
INFIX.

Stacks

38

INFIX

POSTFIX

xy*z

Stacks

39

INFIX

POSTFIX

xy*z

THE OPERANDS FOR - ARE NOT YET


IN POSTFIX, SO - MUST BE
TEMPORARILY SAVED SOMEWHERE.
(STACK)
Stacks

40

INFIX

POSTFIX

xy*z

xy

Stacks

41

INFIX

POSTFIX

xy*z

xy

THE OPERANDS FOR * ARE NOT YET


IN POSTFIX, SO * MUST BE
TEMPORARILY SAVED SOMEWHERE,
AND RESTORED BEFORE -.
Stacks

42

INFIX

POSTFIX

xy*z

xyz

Stacks

43

INFIX

POSTFIX

xy*z

xyz*

Stacks

44

Suppose, instead, we started with


x*y-z
After moving x to postfix, * is
temporarily saved, and then y is
appended to postfix. What happens when
- is accessed?
INFIX

POSTFIX

x*y z

xy
Stacks

45

Stacks

46

THE TEMPORARY STORAGE


FACILITY IS A STACK.

HERE IS THE STRATEGY FOR


MAINTAINING THE STACK:

Stacks

47

Converting Infix to Postfix

Analysis:

Operands are in same order in infix and postfix


Operators occur later in postfix

Strategy:

Send operands straight to output


Send higher precedence operators first
If same precedence, send in left to right order
Hold pending operators on a stack

Stacks

48

FOR EACH OPERATOR IN INFIX:


LOOP UNTIL OPERATOR PUSHED:
IF OPERATOR STACK IS EMPTY,
PUSH
ELSE IF INFIX OPERATOR HAS
GREATER PRECEDENCE
THAN TOP OPERATOR
ON STACK,
PUSH
ELSE
POP AND APPEND TO POSTFIX
Stacks

49

INFIX GREATER, PUSH

Stacks

50

CONVERT FROM INFIX TO POSTFIX:

INFIX

POSTFIX

a+b*c/d-e
Stacks

51

INFIX

POSTFIX

a+b*c/de

abc*d/+e

/
*
+
OPERATOR STACK
Stacks

52

WHAT ABOUT PARENTHESES?


LEFT PARENTHESIS: PUSH, BUT
WITH LOWEST PRECEDENCE.
RIGHT PARENTHESIS:KEEP POPPING
AND APPENDING TO POSTFIX UNTIL
( POPPED; PITCH ( AND PROCEED.
Stacks

53

CONVERT TO POSTFIX:

x * (y + z)

Stacks

54

INFIX
x * (y + z)

POSTFIX
xyz+*

+
(
*
OPERATOR STACK

Stacks

55

Stacks

56

Exercise

Convert the following expression to postfix:

a+b-(c+d*e/(fg))*(h+i)

Stacks

57

Evaluating a Postfix
Expression.

We describe how to parse and evaluate a


postfix expression.
We read the tokens in one at a time.
If it is an integer, push it on the stack
If it is a binary operator, pop the top two
elements from the stack, apply the operator,
and push the result back on the stack.

Stacks

58

593+42**7
Stack Operations
Output
+*

push(5);
push(9);
push(3);
push(pop() + pop())
push(4);
push(2);
push(pop() * pop())
push(pop() * pop()) 5 96
push(pop() + pop())
push(pop() * pop())
Stacks

5
59
593
5 12
5 12 4
5 12 4 2
5 12 8
push(7) 5 96 7
5 103
515
59

TO DECIDE WHAT ACTION TO TAKE IN


CONVERTING FROM INFIX TO
POSTFIX, ALL WE NEED TO KNOW IS
THE CURRENT CHARACTER IN INFIX
AND THE TOP CHARACTER ON
OPERATOR STACK.

Stacks

60

THE FOLLOWING TRANSITION


MATRIX SPECIFIES THE TRANSITION
FROM INFIX NOTATION TO POSTFIX
NOTATION:

Stacks

61

TOP CHARACTER ON STACK

I
N
F
I
X
C

identifier
)
(
+,-

H
A

*,/

empty

+,-

*,/

empty

APPEND APPEND APPEND


TO
TO
TO
POSTFIX POSTFIX POSTFIX

APPEND
TO
POSTFIX

POP;
POP TO POP TO
PITCH ( POSTFIX POSTFIX
PUSH
PUSH
PUSH

ERROR

PUSH

PUSH

POP TO
POSTFIX

POP TO
POSTFIX

PUSH

PUSH

PUSH

PUSH

ERROR

POP TO
POSTFIX

POP TO
POSTFIX
POP TO
POSTFIX

Stacks

DONE

62

Stacks

63

STACK APPLICATION

EVALUATING A

Stacks

64

Can be done with 1 stack

Whenever an operand is encountered, push


onto stack
Whenever operator is encountered, pop
required number of arguments from operand
stack and evaluate
Push result back onto stack

Stacks

65

Algorithm for eval


1.
2.

3.
4.
5.
6.
7.
8.
9.
10.
11.

Empty the operand stack


while there are more tokens
Get the next token
if the first character of the token is a digit
Push the integer onto the stack
else if the token is an operator
Pop the right operand off the stack
Pop the left operand off the stack
Evaluate the operation
Push the result onto the stack
Pop the stack and return the result
Stacks

66

R P N (R e v e r s e P o lis h N o ta tio n ) e x p r e s s io n

S c an o f E x p re s s io n a n d A c tio n C u rre n t o p e ran d S tac k


1 . I d e n t if y 2 a s a n o p e r a n d .
P u s h in t e g e r 2 o n t h e s t a c k .

2 . I d e n t if y 3 a s a n o p e r a n d .
P u s h in t e g e r 3 o n t h e s t a c k .

3 . I d e n t if y + a s a n o p e r a t o r
B e g in t h e p r o c e s s o f e v a lu a t in g + .

4 . g e tO p e r a n d s ( ) p o p s s ta c k
t w ic e a n d a s s ig n s 3 t o
r ig h t a n d 2 t o le f t .

o p e ran d S tac k e m p ty

5 . c o m p u t e ( ) e v a lu a t e s le f t + r ig h t
a n d r e t u r n s t h e v a lu e 5 . R e t u r n
v a lu e is p u s h e d o n t h e s t a c k .
Stacks

67

Another Example
Expression:

5 3 - 6 + 8 2 / 1 2 + - *

3
5

6
2

Execute 5 - 3
1
4
8

4
8

Execute 8 / 2

Execute 2 + 6

Execute Execute
1+2
4-3
Stacks

8
Execute
8*1
68

IN PREFIX NOTATION, AN OPERATOR


IMMEDIATELY PRECEDES ITS
OPERANDS.

Stacks

69

INFIX
a+b

PREFIX
+ab

a * (b + c)

*a+bc

a*b+c

+*abc

IN PREFIX NOTATION, AS IN POSTFIX,


THERE ARE NO PARENTHESES.
Stacks

70

TWO STACKS ARE USED:


OPERATOR STACK: SAME RULES AS
FOR POSTFIX STACK
OPERAND STACK: TO HOLD THE
OPERANDS

Stacks

71

WHENEVER opt IS POPPED FROM


OPERATOR STACK, opd1 AND THEN
opd2 ARE POPPED FROM OPERAND
STACK. THE STRING opt + opd2 + opd1
IS PUSHED ONTO OPERAND STACK.
NOTE: opd2 WAS PUSHED BEFORE opd1.

Stacks

72

CONVERT FROM INFIX TO PREFIX:


INFIX
a + (b * c d) / e

Stacks

73

INFIX

PREFIX

a + (b * c d) / e

+a/ *bcde

+a/ *bcde
/ *bcde
e
*bcd
d
*bc
c
b
a

OPERAND
STACK

*
(
+

Stacks

OPERATOR
STACK

74

EXERCISE: CONVERT TO PREFIX

a b + c * (d / e (f + g))

Stacks

75

Exercise

Convert the following expression to prefix:

a+b-(c+d*e/(fg))*(h+i)

Stacks

76

Self-Test

Write the code to reverse an input string


using a stack.
Assuming that you have a stack that contains
colors: stack<color>
write the code to remove all the values of a
specific color while leaving the remaining
values in the same order.

Stacks

77

Stack Implementations

Array based

Linked List based

Where is top?
How are elements added, removed?
Where is top?
How are elements added, removed?

Efficiency of operations

Stacks

78

Array Based Stack


Where
should top be?
Implementation
12
15
5
2

[0]

array

3
4

What are array values?


s.push (20)

stack

s.pop( )
Stacks

79

Growable Array-based Stack

In a push operation, when


the array is full, instead of
throwing an exception, we
can replace the array with a
larger one
How large should the new
array be?

incremental strategy: increase


the size by a constant c
doubling strategy: double the
size

Stacks

Algorithm push(o)
if t = S.length 1 then
A new array of
size
for i 0 to t do
A[i] S[i]
SA
tt+1
S[t] o

80

Comparison of the Strategies

We compare the incremental strategy and the


doubling strategy by analyzing the total time T(n)
needed to perform a series of n push operations
We assume that we start with an empty stack
represented by an array of size 1
We call amortized time of a push operation the
average time taken by a push over the series of
operations, i.e., T(n)/n

Stacks

81

Incremental Strategy
Analysis

We replace the array k = n/c times


The total time T(n) of a series of n push
operations is proportional to
n + c + 2c + 3c + 4c + + kc =
n + c(1 + 2 + 3 + + k) =
n + ck(k + 1)/2
Since c is a constant, T(n) is O(n + k2), i.e., O(n2)
The amortized time of a push operation is O(n)

Stacks

82

Doubling Strategy Analysis

We replace the array k = log2 n


times
The total time T(n) of a series of n geometric series
push operations is proportional to
2
n + 1 + 2 + 4 + 8 + + 2k =
4
1 1
n 2k + 1 1 = 2n 1
T(n) is O(n)
8
The amortized time of a push
operation is O(1)

Stacks

83

Linked List Implementation


to p

fro nt

C
B

L in k e d L is t

S ta c k

s.push (F)
s.pop( )

Stacks

84

Stack with a Singly Linked


List

We can implement a stack with a singly linked list


The top element is stored at the first node of the list
The space used is O(n) and each operation of the Stack ADT
takes O(1) time
nodes

elements
Stacks

85

Comparison of stack
Implementations
The code for the vector version is very similar to the

implementation in the C++ standard library.


By using delegation, we avoid having to implement the
operations ourselves and are assured of O(1)
performance.
Using the standard containers has a space penalty.

vector allocates additional space to provide ammortized constant


insertion time.
list uses a double linked list which has unneeded pointers.

Using a single linked list allocates space for the links, but
these are necessary.
Using a single linked list also provides O(1) performance.
Stacks

86

Summary Slide 1

- Stack

- Storage Structure with insert (push) and erase (pop)


operations occur at one end, called the top of the
stack.
- The last element in is the first element out of the
stack, so a stack is a LIFO structure.

Stacks

87

87

Summary Slide 2

- Recursion

- The system maintains a stack of activation records


that specify:
1) the function arguments
2) the local variables/objects
3) the return address
- The system pushes an activation record when
calling a function and pops it when returning.

Stacks

88

88

Summary Slide 3

- Postfix / RPN Expression Notation


- places the operator after its operands
- easy to evaluate using a single stack to hold
operands.
- The rules:
1) Immediately push an operand onto the stack.
2) For a binary operator, pop the stack twice, perform the
operation, and push the result onto the stack.

3)

At the end a single value remains on the stack. This is


the value of the expression.

Stacks

89

89

Summary Slide 4

- Infix notation

- A binary operator appears between its operands.


- More complex than postfix, because it requires the
use of operator precedence and parentheses.
- In addition, some operators are left-associative, and
a few are right-associative.

Stacks

90

90

You might also like