Skip to content

Commit e9c1860

Browse files
committed
Merge pull request kodecocodes#49 from aliHafizji/master
Shunting yard algorithm
2 parents cd2fe96 + ea0df5b commit e9c1860

File tree

7 files changed

+686
-0
lines changed

7 files changed

+686
-0
lines changed

Shunting Yard/README.markdown

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Shunting Yard Algorithm
2+
3+
Any mathematical expression that we write is expressed in a notation known as Infix Notation.
4+
5+
For example:
6+
7+
**A + B * C**
8+
9+
In the above expression the operator is placed between operands hence the expression is said to be in Infix form.
10+
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.
11+
12+
Now, think about the way the above expression is evaluated, you would first multiply B and C then add the result to A. This is because multiplication has
13+
higher precedence than addition. We humans can easily understand the precedence of operators, but a machine needs to be given instructions about each operator. If you were to
14+
write an algorithm that parsed and evaluated the infix notation you will realize that it's a tedious process. You'd have to parse the expression
15+
multiple times to know what operation to perform first. As the number of operators increase so does the complexity.
16+
17+
## Postfix notations / Reverse Polish Notation
18+
19+
An expression when represented in postfix form will not have any brackets and neither will you have to worry about scanning for operator precedence. This makes it easy for the computer to evaluate
20+
expressions since the order in which the operator need to be applied is fixed.
21+
22+
For example:
23+
24+
**A B C * +**
25+
26+
The above is the postfix representation of the example in the previous section. The operators come after the corresponding operands.
27+
28+
### Evaluating a postfix expression
29+
30+
A stack is used to evaluate a postfix expression. Here is the pseudocode:
31+
32+
1. Read postfix expression token by token
33+
2. If the token is an operand, push it into the stack
34+
3. If the token is a binary operator,
35+
1. Pop the two top most operands from the stack
36+
2. Apply the binary operator with thetwo operands
37+
3. Push the result into the stack
38+
4. Finally, the value of the whole postfix
39+
expression remains in the stack
40+
41+
Using the above psuedocode the evaluation on the stack would be as follows:
42+
43+
| Expression | Stack |
44+
| ------------- | --------|
45+
| A B C * + | |
46+
| B C * + | A |
47+
| C * + | A, B |
48+
| * + | A, B, C |
49+
| + | A, D |
50+
| | E |
51+
52+
Where **D = B * C** and **E = A + D.**
53+
54+
As seen above a postfix operation is relatively easy to evaluate as the order in which the operators need to be applied is predecided.
55+
56+
## Shunting yard algorithm
57+
58+
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.
59+
60+
Here is the psedocode of the algorithm:
61+
62+
1. For all the input tokens
63+
1. Read the next token
64+
2. If token is an operator (x)
65+
1. While there is an operator (y) at the top of the operators stack and either (x) is left-associative and its precedence is less or equal to that of (y), or (x) is right-associative and its precedence is less than (y)
66+
1. Pop (y) from the stack
67+
2. Add (y) output buffer
68+
2. Push (x) on the stack
69+
3. Else If token is left parenthesis, then push it on the stack
70+
4. Else If token is a right parenthesis
71+
1. Until the top token (from the stack) is left parenthesis, pop from the stack to the output buffer
72+
2. Also pop the left parenthesis but don’t include it in the output buffer
73+
7. Else add token to output buffer
74+
2. While there are still operator tokens in the stack, pop them to output
75+
76+
### How does it work
77+
78+
Let's take a small example and see how the psuedocode works.
79+
80+
**4 + 4 * 2 / ( 1 - 5 )**
81+
82+
| Operator | Precedence | Associativity |
83+
| ---------| -------------| ----------------|
84+
| ^ | 10 | Right |
85+
| * | 5 | Left |
86+
| / | 5 | Left |
87+
| + | 0 | Left |
88+
| - | 0 | Left |
89+
90+
The above table describes the precedence and the associativity for each operator. The same values are used in the algorithm.
91+
92+
| Token | Action | Output | Operator stack |
93+
|-------|---------------------------------------------|-------------------|----------------|
94+
| 3 | Add token to output | 4 | |
95+
| + | Push token to stack | 4 | + |
96+
| 4 | Add token to output | 4 4 | + |
97+
| * | Push token to stack | 4 4 | * + |
98+
| 2 | Add token to output | 4 4 2 | * + |
99+
| / | * Pop stack to output * Push token to stack | 4 4 2 * | / + |
100+
| ( | Push token to stack | 4 4 2 * | ( / + |
101+
| 1 | Add token to output | 4 4 2 * 1 | ( / + |
102+
| - | Push token to stack | 4 4 2 * 1 | - ( / + |
103+
| 5 | Add token to output | 4 4 2 * 1 5 | - ( / + |
104+
| ) | * Pop stack to output * Pop stack | 4 4 2 * 1 5 - | / + |
105+
| end | Pop entire stack to output | 4 4 2 * 1 5 - / + | |
106+
107+
108+
# See Also
109+
110+
[Shunting yard algorithm on Wikipedia](https://en.wikipedia.org/wiki/Shunting-yard_algorithm)
111+
112+
*Written for the Swift Algorithm Club by [Ali Hafizji](http://www.github.com/aliHafizji)*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
//: Playground - noun: a place where people can play
2+
3+
import Foundation
4+
5+
internal enum OperatorAssociativity {
6+
case LeftAssociative
7+
case RightAssociative
8+
}
9+
10+
public enum OperatorType: CustomStringConvertible {
11+
case Add
12+
case Subtract
13+
case Divide
14+
case Multiply
15+
case Percent
16+
case Exponent
17+
18+
public var description: String {
19+
switch self {
20+
case Add:
21+
return "+"
22+
case Subtract:
23+
return "-"
24+
case Divide:
25+
return "/"
26+
case Multiply:
27+
return "*"
28+
case Percent:
29+
return "%"
30+
case Exponent:
31+
return "^"
32+
}
33+
}
34+
}
35+
36+
public enum TokenType: CustomStringConvertible {
37+
case OpenBracket
38+
case CloseBracket
39+
case Operator(OperatorToken)
40+
case Operand(Double)
41+
42+
public var description: String {
43+
switch self {
44+
case OpenBracket:
45+
return "("
46+
case CloseBracket:
47+
return ")"
48+
case Operator(let operatorToken):
49+
return operatorToken.description
50+
case Operand(let value):
51+
return "\(value)"
52+
}
53+
}
54+
}
55+
56+
public struct OperatorToken: CustomStringConvertible {
57+
58+
var operatorType: OperatorType
59+
60+
init(operatorType: OperatorType) {
61+
self.operatorType = operatorType
62+
}
63+
64+
var precedance: Int {
65+
switch operatorType {
66+
case .Add, .Subtract:
67+
return 0
68+
case .Divide, .Multiply, .Percent:
69+
return 5;
70+
case .Exponent:
71+
return 10
72+
}
73+
}
74+
75+
var associativity: OperatorAssociativity {
76+
switch operatorType {
77+
case .Add, .Subtract, .Divide, .Multiply, .Percent:
78+
return .LeftAssociative;
79+
case .Exponent:
80+
return .RightAssociative
81+
}
82+
}
83+
84+
public var description: String {
85+
return operatorType.description
86+
}
87+
}
88+
89+
func <=(left: OperatorToken, right: OperatorToken) -> Bool {
90+
if left.precedance <= right.precedance {
91+
return true
92+
}
93+
return false
94+
}
95+
96+
func <(left: OperatorToken, right: OperatorToken) -> Bool {
97+
if left.precedance < right.precedance {
98+
return true
99+
}
100+
return false
101+
}
102+
103+
public struct Token: CustomStringConvertible {
104+
105+
var tokenType: TokenType
106+
107+
init(tokenType: TokenType) {
108+
self.tokenType = tokenType
109+
}
110+
111+
init(operand: Double) {
112+
tokenType = .Operand(operand)
113+
}
114+
115+
init(operatorType: OperatorType) {
116+
tokenType = .Operator(OperatorToken(operatorType: operatorType))
117+
}
118+
119+
var isOpenBracket: Bool {
120+
switch tokenType {
121+
case .OpenBracket:
122+
return true
123+
default:
124+
return false
125+
}
126+
}
127+
128+
var isOperator: Bool {
129+
switch tokenType {
130+
case .Operator(_):
131+
return true
132+
default:
133+
return false
134+
}
135+
}
136+
137+
var operatorToken: OperatorToken? {
138+
switch tokenType {
139+
case .Operator(let operatorToken):
140+
return operatorToken
141+
default:
142+
return nil
143+
}
144+
}
145+
146+
public var description: String {
147+
return tokenType.description
148+
}
149+
}
150+
151+
public class InfixExpressionBuilder {
152+
153+
private var expression = Array<Token>()
154+
155+
public func addOperator(operatorType: OperatorType) -> InfixExpressionBuilder {
156+
expression.append(Token(operatorType: operatorType))
157+
return self
158+
}
159+
160+
public func addOperand(operand: Double) -> InfixExpressionBuilder {
161+
expression.append(Token(operand: operand))
162+
return self
163+
}
164+
165+
public func addOpenBracket() -> InfixExpressionBuilder {
166+
expression.append(Token(tokenType: .OpenBracket))
167+
return self
168+
}
169+
170+
public func addCloseBracket() -> InfixExpressionBuilder {
171+
expression.append(Token(tokenType: .CloseBracket))
172+
return self
173+
}
174+
175+
public func build() -> Array<Token> {
176+
// Maybe do some validation here
177+
return expression
178+
}
179+
}
180+
181+
// This returns the result of the shunting yard algorithm
182+
public func reversePolishNotation(expression: Array<Token>) -> String {
183+
184+
var tokenStack = Stack<Token>()
185+
var reversePolishNotation = [Token]()
186+
187+
for token in expression {
188+
switch token.tokenType {
189+
case .Operand(_):
190+
reversePolishNotation.append(token)
191+
break
192+
case .OpenBracket:
193+
tokenStack.push(token)
194+
break
195+
case .CloseBracket:
196+
while tokenStack.count > 0 {
197+
if let tempToken = tokenStack.pop() where !tempToken.isOpenBracket {
198+
reversePolishNotation.append(tempToken)
199+
} else {
200+
break
201+
}
202+
}
203+
break
204+
case .Operator(let operatorToken):
205+
206+
for tempToken in tokenStack.generate() {
207+
if !tempToken.isOperator {
208+
break
209+
}
210+
211+
if let tempOperatorToken = tempToken.operatorToken {
212+
213+
if operatorToken.associativity == .LeftAssociative && operatorToken <= tempOperatorToken
214+
|| operatorToken.associativity == .RightAssociative && operatorToken < tempOperatorToken {
215+
216+
reversePolishNotation.append(tokenStack.pop()!)
217+
} else {
218+
break
219+
}
220+
}
221+
}
222+
223+
tokenStack.push(token)
224+
break
225+
}
226+
}
227+
228+
while tokenStack.count > 0 {
229+
reversePolishNotation.append(tokenStack.pop()!)
230+
}
231+
232+
return reversePolishNotation.map({token in
233+
return token.description
234+
}).joinWithSeparator(" ")
235+
}
236+
237+
print(reversePolishNotation(InfixExpressionBuilder().addOperand(3).addOperator(.Add).addOperand(4).addOperator(.Multiply).addOperand(2).addOperator(.Divide).addOpenBracket().addOperand(1).addOperator(.Subtract).addOperand(5).addCloseBracket().addOperator(.Exponent).addOperand(2).addOperator(.Exponent).addOperand(3).build()))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Foundation
2+
3+
public struct Stack<T> {
4+
private var array = [T]()
5+
6+
public init() {
7+
array = []
8+
}
9+
10+
public var isEmpty: Bool {
11+
return array.isEmpty
12+
}
13+
14+
public var count: Int {
15+
return array.count
16+
}
17+
18+
public mutating func push(element: T) {
19+
array.append(element)
20+
}
21+
22+
public mutating func pop() -> T? {
23+
if isEmpty {
24+
return nil
25+
} else {
26+
return array.removeLast()
27+
}
28+
}
29+
30+
public func peek() -> T? {
31+
return array.last
32+
}
33+
}
34+
35+
extension Stack: SequenceType {
36+
public func generate() -> AnyGenerator<T> {
37+
var curr = self
38+
return anyGenerator {
39+
_ -> T? in
40+
return curr.pop()
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)