Topics › Stacks and Queues › Prefix, Infix, PostFix Conversion Problems
Infix to Prefix Conversion
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a valid infix expression, the everyday notation where each binary operator sits between its operands, and must return the equivalent prefix expression (Polish notation), where each operator comes before its two operands. Operands are single letters or digits. Operators are + - * / ^, and round brackets may appear.
Infix needs rules to be unambiguous, and the conversion must respect them:
- Precedence:
^binds tightest, then*and/, then+and-. - Associativity:
+ - * /are left-associative (a-b-cmeans(a-b)-c), while^is right-associative (a^b^cmeansa^(b^c)). - Brackets override both.
Constraints: the input is valid, with length up to about 10^4.
Example 1
infix = "x+y*z/w+u"
prefix = "++x/*yzwu" // ((x + ((y*z)/w)) + u)
Example 2
infix = "(A-B/C)*(A/K-L)"
prefix = "*-A/BC-/AKL" // brackets force both subtractions before the multiplication
Example 3
infix = "a^b^c"
prefix = "^a^bc" // right-associative: a ^ (b ^ c)
The one rule both approaches share. Scanning left to right, operators wait on a stack until it is safe to apply them. When a new operator arrives, the operator on top of the stack must be applied first if it has higher precedence, or equal precedence and the incoming operator is left-associative. That is why a-b-c applies the first - before pushing the second, while a^b^c lets the first ^ wait so the second one binds first.
Approach 1: Two stacks, building prefix strings directly
Intuition. This is the classic two-stack evaluator for infix expressions, the same one a calculator uses, with one change: instead of numbers, the operand stack holds prefix strings. An operand is a prefix expression of length one. “Applying” an operator means popping it, popping its right and left operand strings, and pushing op + left + right. When the input ends, apply everything that is left, and the single string on the operand stack is the answer.
Brackets are handled the usual way: ( is pushed as a barrier; ) applies operators until the matching ( and then discards it. The barrier also stops the precedence loop, so nothing inside a bracket is combined with anything outside it too early.
Algorithm.
- Keep
operands(strings) andops(characters). - For each character
c:- Operand: push it onto
operands. (: push ontoops.): reduce until the top ofopsis(, then pop the(.- Operator: while
opsis not empty, its top is not(, and the top must be applied beforec, reduce. Then pushc.
- Operand: push it onto
- Reduce until
opsis empty, and return the top ofoperands.
static String twoStacks(String infix) {
Deque<String> operands = new ArrayDeque<>();
Deque<Character> ops = new ArrayDeque<>();
for (int i = 0; i < infix.length(); i++) {
char c = infix.charAt(i);
if (isOperand(c)) {
operands.push(String.valueOf(c));
} else if (c == '(') {
ops.push(c);
} else if (c == ')') {
while (ops.peek() != '(') reduce(operands, ops);
ops.pop(); // discard the matching '('
} else {
while (!ops.isEmpty() && ops.peek() != '(' && appliesBefore(ops.peek(), c)) reduce(operands, ops);
ops.push(c);
}
}
while (!ops.isEmpty()) reduce(operands, ops);
return operands.isEmpty() ? "" : operands.pop();
}
/** True when the operator on the stack must be applied before the incoming one is pushed. */
static boolean appliesBefore(char top, char incoming) {
if (precedence(top) != precedence(incoming)) return precedence(top) > precedence(incoming);
return incoming != '^'; // equal precedence: left-associative operators go first, '^' waits
}
/** Pops one operator and its two operands and pushes the combined prefix string. */
static void reduce(Deque<String> operands, Deque<Character> ops) {
char op = ops.pop();
String right = operands.pop();
String left = operands.pop();
operands.push(op + left + right);
}
Dry run on "x+y*z/w+u":
| char | action | operands (bottom to top) | ops |
|---|---|---|---|
| x | push | x | |
| + | push | x | + |
| y | push | x, y | + |
| * | + is lower, just push |
x, y | + * |
| z | push | x, y, z | + * |
| / | * equal and / is left-assoc: reduce *yz, push / |
x, *yz | + / |
| w | push | x, *yz, w | + / |
| + | reduce /*yzw, then reduce +x/*yzw, push + |
+x/*yzw | + |
| u | push | +x/*yzw, u | + |
| end | reduce | ++x/*yzwu |
Complexity. Time O(n^2) in the worst case: each character is pushed and popped once, but each reduction copies both operand strings, and a long chain like a+a+a+... re-copies the growing prefix string every time. Space O(n).
Approach 2: Optimal, reverse, convert to postfix, reverse again
Intuition. There is a neat relationship between prefix and postfix. Take the expression tree and mirror it, swapping the left and right operand of every operator. Then the postfix of the mirrored tree is exactly the reverse of the prefix of the original tree. (By induction: the postfix of the mirror of op(L, R) is post(mirror R) + post(mirror L) + op, which is rev(pre R) + rev(pre L) + op = rev(op + pre L + pre R).)
Reversing the infix string produces the mirrored expression, as long as we also swap ( with ) so brackets still open before they close. Then we can reuse the standard linear infix-to-postfix algorithm on the reversed string and reverse its output.
There is one trap. Mirroring flips associativity. The original a-b-c is (a-b)-c; its mirror must be c-(b-a), which groups to the right. Likewise the mirror of a^(b^c) is (c^b)^a, which groups to the left. So, on the reversed string, ties are broken the opposite way from the normal postfix algorithm: an equal-precedence operator on the stack is popped only when the incoming operator is ^.
Algorithm.
- Reverse the infix string and swap every
(with). - Run infix to postfix on it: operands go straight to the output;
(is pushed;)pops to the output until(; an operator pops while the top has higher precedence, or equal precedence and the incoming operator is^, then is pushed. - Pop the remaining operators to the output.
- Reverse the output.
static String optimal(String infix) {
StringBuilder rev = new StringBuilder(infix).reverse();
for (int i = 0; i < rev.length(); i++) {
char c = rev.charAt(i);
if (c == '(') rev.setCharAt(i, ')');
else if (c == ')') rev.setCharAt(i, '(');
}
StringBuilder out = new StringBuilder(infix.length());
Deque<Character> ops = new ArrayDeque<>();
for (int i = 0; i < rev.length(); i++) {
char c = rev.charAt(i);
if (isOperand(c)) {
out.append(c);
} else if (c == '(') {
ops.push(c);
} else if (c == ')') {
while (ops.peek() != '(') out.append(ops.pop());
ops.pop();
} else {
while (!ops.isEmpty() && ops.peek() != '(' && popsInReversed(ops.peek(), c)) out.append(ops.pop());
ops.push(c);
}
}
while (!ops.isEmpty()) out.append(ops.pop());
return out.reverse().toString();
}
/** Pop rule for the reversed string: associativity is mirrored, so only '^' pops an equal-precedence operator. */
static boolean popsInReversed(char top, char incoming) {
if (precedence(top) != precedence(incoming)) return precedence(top) > precedence(incoming);
return incoming == '^';
}
Dry run on "x+y*z/w+u", reversed to "u+w/z*y+x":
| char | action | output | ops |
|---|---|---|---|
| u | output | u | |
| + | push | u | + |
| w | output | uw | + |
| / | + is lower, push |
uw | + / |
| z | output | uwz | + / |
| * | / equal, * is not ^: no pop, push |
uwz | + / * |
| y | output | uwzy | + / * |
| + | pop *, pop /; + equal, no pop; push |
uwzy*/ | + + |
| x | output | uwzy*/x | + + |
| end | pop all | uwzy*/x++ |
Reversing uwzy*/x++ gives ++x/*yzwu, matching Approach 1.
Complexity. Time O(n): two reversals, and each character is pushed and popped at most once; no string is ever re-copied. Space O(n) for the reversed copy, the operator stack and the output.
Edge cases and pitfalls
- The tie-break on the reversed string. Using the ordinary postfix rule after reversing is the most common bug. On
a-b-cit produces-a-bc, which meansa-(b-c); ona^b^cit produces^^abc, which means(a^b)^c. Both are wrong. The tests cover both expressions. - Swapping brackets. After reversing,
(and)trade places. Forgetting to swap them leaves)before its(, and the stack loop pops past the bottom. - Associativity of
^. This article treats^as right-associative, as in mathematics. Some judges treat it as left-associative. OnlyappliesBeforeandpopsInReversedneed to change. - Redundant brackets.
((a+b))must still produce+ab; brackets never reach the output. - Unsupported input. Spaces, multi-digit numbers and unary minus all need a tokenizer first. The core algorithms work unchanged on tokens.
- Empty input. Both methods return
"".
Related problems
- Infix to Postfix Conversion is the algorithm reused inside Approach 2, with the normal tie-break.
- Prefix to Postfix Conversion converts the output of this problem into postfix without any precedence rules.
- Postfix to Prefix Conversion goes between the bracket-free notations in the other direction.
- Prefix to Infix Conversion undoes this conversion, adding brackets back.
- Balanced Paranthesis is the stack check that guarantees the brackets handled here are well formed.