Stack Applications
CS 250 Data Structures and Algorithms
Prof. Dr. Faisal Shafait
1 / 79
Stack Application
Learning Objectives
In this lecture you will learn
Different applications designs for Stack
How stacks find place in parsing, managing function calls, and
evaluation and conversion to reverse-Polish notation.
2 / 79
Stack Application
Reverse-Polish notation: overview
Notation. we can place the operands first, followed by the operator:
(3 + 4) × 5 − 6
3 4 + 5 × 6 −
Parsing. reads left-to-right and performs any operation on the last two
operands.
3 4 + 5 × 6 −
7 5 × 6 −
35 6 −
29
This is called reverse-Polish notation after the mathematician Jan
Lukasiewicz.
3 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
4 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
5 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
6 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
7 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
8 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
9 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
10 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
11 / 79
Stack Application
Reverse-Polish notation: overview
Other examples:
3 4 5 × + 6 −
3 20 + 6 −
23 6 −
17
3 4 5 6 − × +
3 4 −1 × +
3 −4 +
−1
12 / 79
Stack Application
Reverse-Polish notation: overview
Benefits.
no ambiguity with no brackets are required.
used by a computer to perform computations,
operands must be loaded into registers before operations can be
performed on them.
can be processed using stacks.
13 / 79
Stack Application
Reverse-Polish notation: examples
Reverse-Polish notation is used with some programming languages.
for example, postscript, pdf, and HP calculators.
The concept is used when writing assembly language code,
an operator cannot perform an operation until operands are
loaded into registers.
mov ax, 40 ; Load 40 into register ax
mov bx, 20 ; Load 20 into register bx
add ax, bx ; Add ax into bx
14 / 79
Stack Application
Reverse-Polish notation: evaluation
Implementation. simplest method to parse reverse-Polish notation is
to use an operand stack,
operands are processed by pushing them onto the stack.
operator is processed as,
pop the last two items off the operand stack,
perform the operation, and
push the result back onto the stack.
15 / 79
Stack Application
Reverse-Polish notation: evaluation
Two-stack algorithm (E. W. Dijkstra).
Input: a post-fix expression
Output: result of the evaluation
s := STACK()
for each token in expression:
if IS-OPERAND(token):
s.PUSH(token)
else if IS-OPERATOR(token):
b := s.POP() // The second operand is popped first
a := s.POP()
result := EVALUATE(a,b,token)
s.PUSH(result)
16 / 79
Stack Application
Reverse-Polish notation: evaluation
Two-stack algorithm (E. W. Dijkstra).
Input: a post-fix expression
Output: result of the evaluation
s := STACK()
for each token in expression:
if IS-OPERAND(token):
s.PUSH(token)
else if IS-OPERATOR(token):
b := s.POP() // The second operand is popped first
a := s.POP()
result := EVALUATE(a,b,token)
s.PUSH(result)
17 / 79
Stack Application
Reverse-Polish notation: evaluation
Two-stack algorithm (E. W. Dijkstra).
Input: a post-fix expression
Output: result of the evaluation
s := STACK()
for each token in expression:
if IS-OPERAND(token):
s.PUSH(token)
else if IS-OPERATOR(token):
b := s.POP() // The second operand is popped first
a := s.POP()
result := EVALUATE(a,b,token)
s.PUSH(result)
18 / 79
Stack Application
Reverse-Polish notation: evaluation
Two-stack algorithm (E. W. Dijkstra).
Input: a post-fix expression
Output: result of the evaluation
s := STACK()
for each token in expression:
if IS-OPERAND(token):
s.PUSH(token)
else if IS-OPERATOR(token):
b := s.POP() // The second operand is popped first
a := s.POP()
result := EVALUATE(a,b,token)
s.PUSH(result)
19 / 79
Stack Application
Reverse-Polish notation: evaluation
Two-stack algorithm (E. W. Dijkstra).
Input: a post-fix expression
Output: result of the evaluation
s := STACK()
for each token in expression:
if IS-OPERAND(token):
s.PUSH(token)
else if IS-OPERATOR(token):
b := s.POP() // The second operand is popped first
a := s.POP()
result := EVALUATE(a,b,token)
s.PUSH(result)
20 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
21 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
22 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
23 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
24 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
25 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
26 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
27 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
28 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
29 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
30 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
31 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
32 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
33 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
34 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
35 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
36 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
37 / 79
Stack Application
Reverse-Polish notation: evaluation
Evaluate the following reverse-Polish expression using a stack:
123 + 456 × −7 × + − 89 × +
38 / 79
Stack Application
Reverse-Polish notation: evaluation
Result.
123 + 456 × −7 × + − 89 × +
evaluates to the value on the top: 250
The equivalent in-fix notation is
((1 − ((2 + 3) + ((4 − (5 × 6)) × 7))) + (8 × 9))
We reduce the parentheses using order-of-operations:
1 − (2 + 3 + (4 − 5 × 6) × 7) + 8 × 9
39 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − 2 + 3 + 4 − 5 × 6 × 7 + 8 × 9 = −132
the reverse-Polish notation is,
1 2 − 3 + 4 + 5 6 7 × × − 8 9 × +
40 / 79
Stack Application
Reverse-Polish notation: conversion
The shunting-yard algorithm for parsing mathematical expressions
specified in infix notation.
invented by Edsger Dijkstra.
operation resembles that of a railroad shunting yard.
similar to evaluation of RPN, the algorithm is stack-based.
For the conversion,
two strings, the input and the output.
a stack that holds operators not yet added to the output queue.
41 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
42 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
43 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
44 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
45 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
46 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
47 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
48 / 79
Stack Application
Reverse-Polish notation: conversion
Input: infix expression
Output: post-fix expression
s := STACK()
for each token in expression:
if IS-OPERAND(token):
output.APPEND(token)
else if IS-OPERATOR(token):
while token.PRECEDENCE() <= s.PEEK().PRECEDENCE():
output.APPEND(s.POP())
s.PUSH(token)
else if token == ’(’:
s.PUSH(token)
else if token == ’)’:
Until s.PEEK() != ’(’:
output.APPEND(s.POP())
s.POP()
while not s.IS-EMPTY
output.APPEND(s.POP())
49 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
50 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1
51 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1
52 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1
53 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2
54 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2
55 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3
56 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 +
57 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 +
58 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4
59 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4
60 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5
61 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5
62 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6
63 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × −
64 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × −
65 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7
66 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × +
67 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × + −
68 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × + − 8
69 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × + − 8
70 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × + − 8 9
71 / 79
Stack Application
Reverse-Polish notation: conversion
For example,
1 − ( 2 + 3 + ( 4 − 5 × 6 ) × 7 ) + 8 × 9
Output buffer,
1 2 3 + 4 5 6 × − 7 × + − 8 9 × +
72 / 79
Stack Application Parsing
Application: parsing
Most parsers use stacks.
Examples.
Matching tags in XHTML/XML/HTML
In C/C++/Java, matching
parentheses ( ... )
brackets [ ... ], and
braces { ... }
73 / 79
Stack Application Parsing
Application: parsing XHTML
XHTML is made of nested
opening tags, e.g., <some_identifier>, and
matching closing tags, e.g., </some_identifier>
1 <html >
2 <head ><title >Hello </title ></head >
3 <body ><p>This appears in the <i>browser </i>.</p></body >
4 </html >
74 / 79
Stack Application Parsing
Application: parsing XHTML
Steps to parse XHTML:
read though the XHTML linearly.
place the opening tags in a stack.
when a closing tag is encountered, check that it matches what is
on top of the stack.
We are finished parsing, and the stack is empty
Possible errors detected.
a closing tag which does not match the opening tag on top of the
stack.
a closing tag when the stack is empty.
the stack is not empty at the end of the document.
75 / 79
Stack Application Parsing
Application: parsing C/C++
Similar to XHTML opening and closing tags to check,
parentheses, brackets, and braces must be similarly nested.
1 int init( int * array , int n ) {
2
3 for ( int i = 0; i < n; ++i ) {
4
5 array[i] = 0;
6 }
7 }
76 / 79
Stack Application Function calls
Application: function calls
Function calls are similar to problem solving.
you write a function to solve a problem.
the function may require sub-problems to be solved; hence, calls
other functions.
once a function is finished, it returns to the function which called it.
The simple features of a stack indicate that,
almost all programming languages are based on function calls.
they are implemented in hardware on all CPUs to facilitate such
function calls.
77 / 79
Stack Application Function calls
Summary
We looked at different designs where a stack is, or can be used.
rather than its implementation.
We briefly considered different applications of stack,
for parsing, managing function calls, and evaluation and
conversion to reverse-Polish notation.
78 / 79
Stack Application Function calls
Reading Material
For further reading, please refer to
Data Structures by Weiss: Chapter 16, Sections 16.1 – 16.3
https://mathworld.wolfram.com/ReversePolishNotation.html
79 / 79