Problem
Convert an infix expression (which uses the standard order of operations with parentheses) to a postfix expression (Reverse Polish Notation).
Pre-requisite - What is infix, postfix and prefix?
What is infix, postfix and prefix?
Examples
Example 1:
Input: "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"
Output: "3 4 2 * 1 5 - 2 3 ^ ^ / +"
Explanation: The infix expression "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3" is converted to the postfix expression "3 4 2 * 1 5 - 2 3 ^ ^ / +".
Example 2:
Input: "a + b * c"
Output: "a b c * +"
Explanation: The infix expression "a + b * c" is converted to the postfix expression "a b c * +".
Evaluation
Once the conversion, we can evaluate the expression using the stack again.
Solution
Method 1 - Shunting-yard Algorithm using Stacks
I used a stack ADT implemented with a linked list, as linked lists allow for dynamic memory allocation.
Converting an infix expression to Reverse Polish Notation can be achieved using the Shunting-yard algorithm by Dijkstra. This algorithm operates in O(n)
time and requires O(n)
space.
The method in this context follows the standard algorithm of comparing precedence between input and stack operators.
Pseudocode
- While tokens are available:
- Read the next token.
- If it’s a number, add it to the output queue.
- If it’s a function token, push it onto the stack.
- If it’s a function argument separator (e.g., a comma):
- Pop operators from the stack to the output queue until a left parenthesis is encountered. If none is found, the separator was misplaced or the parentheses mismatched.
- If it’s an operator (
o1
):- While there’s an operator (
o2
) on top of the stack and either:o1
is left-associative and has precedence less than or equal too2
,- or
o1
is right associative and has less precedence thano2
, - pop
o2
off the stack and onto the output queue.
- Push
o1
onto the operator stack.
- While there’s an operator (
- If it’s a left parenthesis
"("
, push it onto the stack. - If it’s a right parenthesis
")"
:- Pop operators from the stack to the output queue until a left parenthesis is encountered.
- Remove the left parenthesis from the stack but do not add it to the output queue.
- If a function token is on top of the stack, pop it onto the output queue.
- If the stack is exhausted without finding a left parenthesis, the parentheses are mismatched.
- When no more tokens are left:
- While there are operator tokens on the stack:
- If the top stack operator is a parenthesis, the parentheses are mismatched.
- Pop operators from the stack to the output queue.
- While there are operator tokens on the stack:
- Exit.
Operator precedence
The precedence values used in the code are as follows:
Operator | Precedence Value |
---|---|
^ | 4 |
* | 3 |
/ | 3 |
+ | 2 |
- | 2 |
Code
Java
public class Solution {
public String toPostfix(String infix) {
StringBuilder output = new StringBuilder();
Stack<Character> operators = new Stack<>();
Map<Character, Integer> precedence = new HashMap<>();
precedence.put('^', 4);
precedence.put('*', 3);
precedence.put('/', 3);
precedence.put('+', 2);
precedence.put('-', 2);
Map<Character, Boolean> rightAssociative = new HashMap<>();
rightAssociative.put('^', true); // '^' is right associative
for (int i = 0; i < infix.length(); i++) {
char token = infix.charAt(i);
if (Character.isWhitespace(token)) {
continue;
} else if (Character.isLetterOrDigit(token)) {
output.append(token).append(' ');
} else if (token == '(') {
operators.push(token);
} else if (token == ')') {
while (!operators.isEmpty() && operators.peek() != '(') {
output.append(operators.pop()).append(' ');
}
operators.pop(); // Remove the '('
} else if (precedence.containsKey(token)) {
while (!operators.isEmpty() && precedence.containsKey(operators.peek()) &&
((rightAssociative.getOrDefault(token, false) && precedence.get(token) < precedence.get(operators.peek())) ||
(!rightAssociative.getOrDefault(token, false) && precedence.get(token) <= precedence.get(operators.peek())))) {
output.append(operators.pop()).append(' ');
}
operators.push(token);
}
}
while (!operators.isEmpty()) {
output.append(operators.pop()).append(' ');
}
return output.toString().trim();
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.toPostfix("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3")); // Output: 3 4 2 * 1 5 - 2 3 ^ ^ / +
System.out.println(solution.toPostfix("a + b * c")); // Output: a b c * +
}
}
Python
class Solution:
def toPostfix(self, infix: str) -> str:
output: List[str] = []
operators: List[str] = []
precedence = {'^': 4, '*': 3, '/': 3, '+': 2, '-': 2}
right_associative = {'^': True} # '^' is right associative
i = 0
while i < len(infix):
token = infix[i]
if token.isspace():
i += 1
continue
elif token.isalnum(): # token is an operand
output.append(token)
elif token == '(':
operators.append(token)
elif token == ')':
while operators and operators[-1] != '(':
output.append(operators.pop())
operators.pop() # Remove the '('
elif token in precedence:
while (operators and operators[-1] in precedence and
((token in right_associative and precedence[token] < precedence[operators[-1]]) or
(token not in right_associative and precedence[token] <= precedence[operators[-1]]))):
output.append(operators.pop())
operators.append(token)
i += 1
while operators:
output.append(operators.pop())
return ' '.join(output)
# Test the implementation
sol = Solution()
print(sol.toPostfix("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3")) # Output: 3 4 2 * 1 5 - 2 3 ^ ^ / +
print(sol.toPostfix("a + b * c")) # Output: a b c * +
Complexity
- ⏰ Time complexity:
O(n)
wheren
is the length of the infix expression. - 🧺 Space complexity:
O(n)
due to the use of an auxiliary stack.
Dry Run
Lets take some examples.
Example 1 - A*B+C
The expression A * B + C
should convert to A B * C +
.
Step | Current Symbol | Operator Stack | Postfix String |
---|---|---|---|
1 | A | A | |
2 | * | * | A |
3 | B | * | A B |
4 | + | + | A B * {pop * then push +} |
5 | C | + | A B * C |
6 | A B * C + |
Example 2 - A+B*C
The expression A + B * C
should convert to A B C * +
.
Step | Current Symbol | Operator Stack | Postfix String |
---|---|---|---|
1 | A | A | |
2 | + | + | A |
3 | B | + | A B |
4 | * | + * | A B |
5 | C | + * | A B C |
6 | A B C * + |
Example 3 - a/b*(c+(d-e))
The expression a / b * ( c + ( d - e ))
should convert to a b / c d e - + *
.
Step | Current Symbol | Operator Stack | Postfix String |
---|---|---|---|
1 | a | a | |
2 | / | / | a |
3 | b | / | a b |
4 | * | * | a b / |
5 | ( | * ( | a b / |
6 | c | * ( | a b / c |
7 | + | * ( + | a b / c |
8 | ( | * ( + ( | a b / c |
9 | d | * ( + ( | a b / c d |
10 | - | * ( + ( - | a b / c d |
11 | e | * ( + ( - | a b / c d e |
12 | ) | * ( + | a b / c d e - |
13 | ) | * | a b / c d e - + |
14 | a b / c d e - + * |