There is an ancient tradition in mathematics to place an operator between the operands (x + y)
rather than after
the operands xy+
. Form with an operator between operands is called infix notation. The form with an operator
after the operands is called postfix, or Reverse Polish notation. It has a number of advantages over infix
notation when expressing algebraic formulas:
- Any formula can be expressed without parentheses.
- It is convenient for calculating formulas on stacked machines.
- Infix operators have precedence that is arbitrary and undesirable.
For example, we know that ab+c
means (ab)+c
, not a(b+c)
, since it was arbitrarily determined that
multiplication has priority over addition. But does the left shift take precedence over the AND
operation? Who
knows? Reverse Polish notation allows you to eliminate such misunderstandings.
We will consider an algorithm, the idea of which was proposed by E.W. Dijkstra. Let the formula consist of
variables, two-operand operators + - * / ^
, as well as left and right parentheses. For convenience, it is
suggested to insert markers start
and end
before the beginning of the formula and at the end, respectively.
(result expression in RPN)
(here we choose way) [ (,4,+,3,*,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start ]
The diagram shows the paths of movement of an element from the queue to the resulting list. Elements move from left to
right. In a place indicated by the sign ?
, a decision is made on the path of further movement of the element from
the beginning of the queue. The elements can move directly to the resulting list or hit the stack along the way.
Operands (variables) always move directly to the resulting list.
The table shows the dependence of the situation on which operator is next in line and which operator is on the top of the stack.
The
start
element is always pushed onto the stack.
end | + | - | * | / | ^ | ( | ) | |
---|---|---|---|---|---|---|---|---|
start | 4 | 1 | 1 | 1 | 1 | 1 | 1 | 5 |
+ | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 2 |
- | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 2 |
* | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 2 |
. | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 2 |
^ | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 2 |
( | 5 | 1 | 1 | 1 | 1 | 1 | 1 | 3 |
Vertically - the operator at the top of the stack.
Horizontally - the next operator in the queue.
The numbers correspond to the following situations:
- The next operator from the queue is pushed onto the stack.
- The operator at the top of the stack is sent to the end of the resulting list.
- The next operator from the queue and the operator at the top of the stack are removed and disappeared.
- The resulting list contains the expression in reverse Polish notation. End of conversion.
- Fatal error. The input expression is formulated incorrectly.
After each action, the next comparison is made between the operator from the queue and the operator at the top of the stack. Process continues until situation 4 is reached.
The order of variables in infix and postfix notation is the same. However, the order of the operators is not always the same. In reverse Polish notation, statements appear in the order in which they will be executed.
Conversion steps explained
- Initially stack contains
start
item. Input infix expression in queue.
(result expression in RPN)
[ ] (here we choose way) [ (,4,+,3,*,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start ]
- Moving
(
to the stack.
(result expression in RPN)
[ ] (here we choose way) [ 4,+,3,*,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,( ]
- Moving
4
to the result list.
(result expression in RPN)
[ 4 ] (here we choose way) [ +,3,*,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,( ]
- Moving
+
to the stack.
(result expression in RPN)
[ 4 ] (here we choose way) [ 3,*,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,(,+ ]
- Moving
3
to the result list.
(result expression in RPN)
[ 4,3 ] (here we choose way) [ *,20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,(,+ ]
- Moving
*
to the stack.
(result expression in RPN)
[ 4,3 ] (here we choose way) [ 20,),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,(,+,* ]
- Moving
20
to the result list.
(result expression in RPN)
[ 4,3,20 ] (here we choose way) [ ),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,(,+,* ]
- Moving
*
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,* ] (here we choose way) [ ),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,(,+ ]
- Moving
+
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+ ] (here we choose way) [ ),/,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,( ]
- Removing
(
from the stack and removing)
from the input queue.
(result expression in RPN)
[ 4,3,20,*,+ ] (here we choose way) [ /,(,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start ]
- Moving
/
to the stack.
(result expression in RPN)
[ 4,3,20,*,+ ] (here we choose way) [ (,10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/ ]
- Moving
(
to the stack.
(result expression in RPN)
[ 4,3,20,*,+ ] (here we choose way) [ 10,+,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,( ]
- Moving
10
to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10 ] (here we choose way) [ +,3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,( ]
- Moving
+
to the stack.
(result expression in RPN)
[ 4,3,20,*,+,10 ] (here we choose way) [ 3,*,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+ ]
- Moving
3
to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3 ] (here we choose way) [ *,3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+ ]
- Moving
*
to the stack.
(result expression in RPN)
[ 4,3,20,*,+,10,3 ] (here we choose way) [ 3,^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+,* ]
- Moving
3
to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3 ] (here we choose way) [ ^,2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+,* ]
- Moving
^
to the stack.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3 ] (here we choose way) [ 2,-,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+,*,^ ]
- Moving
2
to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2 ] (here we choose way) [ -,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+,*,^ ]
- Moving
^
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^ ] (here we choose way) [ -,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+,* ]
- Moving
*
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,* ] (here we choose way) [ -,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,+ ]
- Moving
+
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+ ] (here we choose way) [ -,12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,( ]
- Moving
-
to the stack.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+ ] (here we choose way) [ 12,) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,- ]
- Moving
12
to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+,12 ] (here we choose way) [ ) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,(,- ]
- Moving
-
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+,12,- ] (here we choose way) [ ) ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/,( ]
- Removing
(
from the stack and removing)
from the input queue.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+,12,- ] (here we choose way) [ ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start,/ ]
- Moving
/
from the stack to the result list.
(result expression in RPN)
[ 4,3,20,*,+,10,3,3,2,^,*,+,12,-,/ ] (here we choose way) [ ]
result <─────────────────────────────────── ? <───────────────── queue
^ │ (input expression)
│ │
│ │
│ (here operators are temporary stored) │
└─────────────── stack <────────────────┘
[ start ]
Input infix expression:
( 4 + 3 * 20 ) / ( 10 + 3 * 3 ^ 2 - 12 )
.
Result RNP expression:4 3 20 * + 10 3 3 2 ^ * + 12 - /
.
Many programming languages have right-associative operators. Let us analyze using the example of the power operator.
2 ^ 2 ^ 3 = 2 ^ (2 ^ 3) = 256 (not 64!)
So, operations executes from right to the left.
The algorithm for calculating an expression in Reverse Polish notation using a stack is quite simple:
- If an operand is encountered, it must be put on the top of the stack.
- If an operator is encountered - you need to perform the specified operation.
To perform the operation, the last two operands are popped from the stack. Note, the number located at the top of the stack is the right-hand operand (not the left-hand one)! This is very important for such operations like division, subtraction and others, where the order of the operands is important.
Therefore, it is necessary to traverse all elements of the input expression.
If, after calculating the expression, more or less than one element remains on the stack - the input expression is not written correctly.
Step | Remaining chain | Stack |
---|---|---|
1 | 4, 3, 20, *, +, 10, 3, 3, 2, ^, *, +, 12, -, / | |
2 | 3, 20, *, +, 10, 3, 3, 2, ^, *, +, 12, -, / | 4.0 |
3 | 20, *, +, 10, 3, 3, 2, ^, *, +, 12, -, / | 4.0, 3.0 |
4 | *, +, 10, 3, 3, 2, ^, *, +, 12, -, / | 4.0, 3.0, 20.0 |
5 | +, 10, 3, 3, 2, ^, *, +, 12, -, / | 4.0, 60.0 |
6 | 10, 3, 3, 2, ^, *, +, 12, -, / | 64.0 |
7 | 3, 3, 2, ^, *, +, 12, -, / | 64.0, 10.0 |
8 | 3, 2, ^, *, +, 12, -, / | 64.0, 10.0, 3.0 |
9 | 2, ^, *, +, 12, -, / | 64.0, 10.0, 3.0, 3.0 |
10 | ^, *, +, 12, -, / | 64.0, 10.0, 3.0, 3.0, 2.0 |
11 | *, +, 12, -, / | 64.0, 10.0, 3.0, 9.0 |
12 | +, 12, -, / | 64.0, 10.0, 27.0 |
13 | 12, -, / | 64.0, 37.0 |
14 | -, / | 64.0, 37.0, 12.0 |
15 | / | 64.0, 25.0 |
16 | 2.56 |
Result: 2.56
Author: Danil Andreev
Thanks for inspiration: agorkov (https://habr.com/ru/post/100869/)