Any mathematics we write is expressed in a notation known as infix notation. For example:
A + B * C
The operator is placed in between the operands, hence the expression is said to be in infix form. If you think about it, any expression that you write on a piece of paper will always be in infix form. This is what we humans understand.
Multiplication has higher precedence than addition, so when the above expression is evaluated you would first multiply B and C, and then add the result to A. We humans can easily understand the precedence of operators, but a machine needs to be given instructions about each operator.
To change the order of evaluation, we can use parentheses:
(A + B) * C
Now A is first added to B and then the sum is multiplied by C.
If you were to write an algorithm that parsed and evaluated expressions in infix notation you will realize that it's a tedious process. You'd have to parse the expression multiple times to know what operation to perform first. As the number of operators increase so does the complexity.
In postfix notation, also known as Reverse Polish Notation or RPN, the operators come after the corresponding operands. Here is the postfix representation of the example from the previous section:
A B C * +
An expression in postfix form will not have any parentheses and neither will you have to worry about scanning for operator precedence. This makes it easy for the computer to evaluate expressions, since the order in which the operators need to be applied is fixed.
Evaluating a postfix expression is easily done using a stack. Here is the pseudocode:
Using the above pseudocode, the evaluation of A B C * + would be as follows:
Expression | Stack |
---|---|
A B C * + | |
B C * + | A |
C * + | A, B |
* + | A, B, C |
+ | A, D |
E |
Where D = B * C and E = A + D.
As seen above, a postfix operation is relatively easy to evaluate as the order in which the operators need to be applied is pre-decided.
The shunting yard algorithm was invented by Edsger Dijkstra to convert an infix expression to postfix. Many calculators use this algorithm to convert the expression being entered to postfix form.
Here is the psedocode of the algorithm:
Let's take a small example and see how the pseudocode works. Here is the infix expression to convert:
4 + 4 * 2 / ( 1 - 5 )
The following table describes the precedence and the associativity for each operator. The same values are used in the algorithm.
Operator | Precedence | Associativity |
---|---|---|
^ | 10 | Right |
* | 5 | Left |
/ | 5 | Left |
+ | 0 | Left |
- | 0 | Left |
Here we go:
Token | Action | Output | Operator stack |
---|---|---|---|
4 | Add token to output | 4 | |
+ | Push token to stack | 4 | + |
4 | Add token to output | 4 4 | + |
* | Push token to stack | 4 4 | * + |
2 | Add token to output | 4 4 2 | * + |
/ | Pop stack to output, Push token to stack | 4 4 2 * | / + |
( | Push token to stack | 4 4 2 * | ( / + |
1 | Add token to output | 4 4 2 * 1 | ( / + |
- | Push token to stack | 4 4 2 * 1 | - ( / + |
5 | Add token to output | 4 4 2 * 1 5 | - ( / + |
) | Pop stack to output, Pop stack | 4 4 2 * 1 5 - | / + |
end | Pop entire stack to output | 4 4 2 * 1 5 - / + |
We end up with the postfix expression:
4 4 2 * 1 5 - / +
Shunting yard algorithm on Wikipedia
Written for the Swift Algorithm Club by Ali Hafizji
Migrated to Swift 3 by Jaap Wijnen