0% found this document useful (0 votes)
29 views

Lecture 8 Stack Applications

The document discusses stack applications such as reverse polish notation. Reverse polish notation writes mathematical expressions with operands preceding operators. It can be evaluated using a stack, where operands are pushed and operators pop operands to perform operations and push results. The document provides examples of reverse polish notation and evaluates expressions using a stack algorithm.

Uploaded by

Abdullah Tahir
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

Lecture 8 Stack Applications

The document discusses stack applications such as reverse polish notation. Reverse polish notation writes mathematical expressions with operands preceding operators. It can be evaluated using a stack, where operands are pushed and operators pop operands to perform operations and push results. The document provides examples of reverse polish notation and evaluates expressions using a stack algorithm.

Uploaded by

Abdullah Tahir
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 79

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

You might also like