Topics › Stacks and Queues › Prefix, Infix, PostFix Conversion Problems
Postfix to Prefix Conversion
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a valid postfix expression (reverse Polish notation, every operator written after its two operands) and must return the equivalent prefix expression (Polish notation, every operator written before its operands). Operands are single letters or digits; every other character is a binary operator such as + - * / ^.
Both notations are bracket-free and need no precedence table: the position of each operator already says exactly which operands it combines. The conversion only rearranges symbols; it never has to decide what binds tighter.
Constraints: the input is a valid expression, with length up to about 10^4.
Example 1
postfix = "AB+CD-*"
prefix = "*+AB-CD" // both mean (A + B) * (C - D)
Example 2
postfix = "ABC/-AK/L-*"
prefix = "*-A/BC-/AKL" // both mean (A - B / C) * (A / K - L)
Example 3
postfix = "abc^^"
prefix = "^a^bc" // a ^ (b ^ c): the grouping survives the conversion
The picture to keep in mind. Every expression is a binary tree whose leaves are operands and whose internal nodes are operators. Postfix is the postorder of that tree (left, right, node) and prefix is the preorder (node, left, right). Converting means reading one traversal and writing the other.
Approach 1: Stack of strings, scanning left to right
Intuition. Postfix was designed to be evaluated with a stack. Read left to right: an operand is pushed, and an operator applies to the two values on top of the stack. We do exactly the same thing, except that instead of numbers the stack holds already-converted prefix strings. An operand is a finished prefix expression of length one. When an operator arrives, the top two strings are its operands, so combining them as operator + left + right produces the prefix form of the bigger sub-expression.
The only thing to get right is the order of the pops. The right operand was finished last, so it is on top: the first pop is the right operand, the second pop is the left operand.
Algorithm.
- Create an empty stack of strings.
- For each character
cfrom left to right:- If
cis an operand, push it as a one-character string. - Otherwise pop
right, popleft, and pushc + left + right.
- If
- Return the single string left on the stack (or
""for an empty input).
static String stackOfStrings(String postfix) {
Deque<String> st = new ArrayDeque<>();
for (int i = 0; i < postfix.length(); i++) {
char c = postfix.charAt(i);
if (isOperand(c)) {
st.push(String.valueOf(c));
} else {
String right = st.pop(); // pushed last, so it is the right operand
String left = st.pop();
st.push(c + left + right);
}
}
return st.isEmpty() ? "" : st.pop();
}
In c + left + right the char is concatenated with a String, so Java performs string concatenation, not integer addition. (Writing c + d + left with two chars first would add their character codes, a classic slip.)
Dry run on "AB+CD-*":
| char | action | stack (bottom to top) |
|---|---|---|
| A | push | A |
| B | push | A, B |
| + | pop B, pop A, push +AB |
+AB |
| C | push | +AB, C |
| D | push | +AB, C, D |
| - | pop D, pop C, push -CD |
+AB, -CD |
| * | pop -CD, pop +AB, push *+AB-CD |
*+AB-CD |
Complexity. Time O(n^2) in the worst case. There are only O(n) pushes and pops, but every concatenation copies both operand strings. On a left-leaning chain such as aa+a+a+..., the string on the stack grows by two characters per operator, so the total copying is 3 + 5 + 7 + ..., which is quadratic. Space O(n) for the stack and its strings.
This is the expected interview answer and is fast enough for typical input sizes. The next approach shows how to make it strictly linear.
Approach 2: Optimal, build the expression tree once
Intuition. The cost in Approach 1 comes from re-copying the same characters every time a sub-expression is wrapped by another operator. We can avoid copying by not producing strings until the very end. Run the same stack algorithm, but push tree nodes instead of strings: an operand becomes a leaf, and an operator becomes a node whose children are the two popped nodes. Creating a node is O(1) no matter how large its subtrees are.
When the scan ends, the stack holds the root of the expression tree. Writing that tree in preorder (node, left subtree, right subtree) is exactly the prefix expression, and a traversal visits each node once.
To avoid recursion (a degenerate chain can be thousands of levels deep), the preorder walk uses an explicit stack: pop a node, write it, then push its right child before its left child so that the left subtree is processed first.
Algorithm.
- If the input is empty, return
"". - Scan left to right with a stack of nodes. Push a leaf for each operand. For an operator, pop
right, popleft, and pushnew Node(op, left, right). - Preorder: push the root onto a
todostack. While it is not empty, pop a node, append its symbol, push its right child if any, then its left child if any. - Return the built string.
static final class Node {
final char symbol;
final Node left, right;
Node(char symbol, Node left, Node right) {
this.symbol = symbol;
this.left = left;
this.right = right;
}
}
/** Approach 2: build the expression tree once, then emit its preorder traversal. O(n) time, O(n) space. */
static String expressionTree(String postfix) {
if (postfix.isEmpty()) return "";
Deque<Node> st = new ArrayDeque<>();
for (int i = 0; i < postfix.length(); i++) {
char c = postfix.charAt(i);
if (isOperand(c)) {
st.push(new Node(c, null, null));
} else {
Node right = st.pop();
Node left = st.pop();
st.push(new Node(c, left, right));
}
}
StringBuilder out = new StringBuilder(postfix.length());
Deque<Node> todo = new ArrayDeque<>();
todo.push(st.pop());
while (!todo.isEmpty()) { // iterative preorder: node, left subtree, right subtree
Node node = todo.pop();
out.append(node.symbol);
if (node.right != null) todo.push(node.right); // pushed first, so it is visited after the left
if (node.left != null) todo.push(node.left);
}
return out.toString();
}
Why the preorder is the prefix expression. By construction each operator node’s left subtree is the left operand and its right subtree is the right operand. Preorder writes the operator, then the whole left operand in prefix form, then the whole right operand in prefix form, which is the recursive definition of prefix notation.
Complexity. Time O(n): one pass to build n nodes, and one traversal that pushes and pops every node once. Space O(n) for the nodes and the two stacks.
Edge cases and pitfalls
- Pop order. In a left-to-right scan the first pop is the right operand. Swapping them silently turns
A-BintoB-A. Commutative operators like+hide the bug, so test with-,/or^; the Java file checks bothab^c^andabc^^, which only differ in grouping. - char plus char.
'+' + 'a'is the integer140, not the string"+a". Make sure at least one operand of the first+is aString. - Single operand and empty input.
"A"stays"A", and""returns""instead of throwing. - Invalid input. Both methods assume validity. To validate, check that the stack holds at least two items before every operator and exactly one at the end.
- Null children in
ArrayDeque.ArrayDequerejectsnull, so the traversal only pushes children that exist. - Multi-character operands. Tokenize first (for example on spaces); the algorithms work the same on tokens.
Related problems
- Prefix to Postfix Conversion goes the other way and scans from the right.
- Postfix to Infix Conversion uses the same left-to-right stack but wraps each combination in brackets.
- Prefix to Infix Conversion is the bracketing version for prefix input.
- Infix to Postfix Conversion is where precedence and associativity have to be handled.
- Infix to Prefix Conversion reaches prefix from infix with a reversal trick.