Topics › Stacks and Queues › Prefix, Infix, PostFix Conversion Problems
Postfix to Infix Conversion
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a valid postfix expression (each operator written after its two operands) and must return the equivalent infix expression (each operator written between its operands), the notation people normally use. Operands are single letters or digits; every other character is a binary operator such as + - * / ^.
Infix is the one notation that is ambiguous without help: a*b+c could mean (a*b)+c or a*(b+c). To keep the output unambiguous without reasoning about precedence, the standard version of this problem asks for a fully parenthesised result: every operator together with its two operands is wrapped in one pair of brackets.
Constraints: the input is a valid expression, with length up to about 10^4.
Example 1
postfix = "ab*c+"
infix = "((a*b)+c)" // multiply first, then add c
Example 2
postfix = "abc++"
infix = "(a+(b+c))" // b + c is formed first, so it is the inner bracket
Example 3
postfix = "a"
infix = "a" // a lone operand gets no brackets
The picture to keep in mind. An expression is a binary tree with operands at the leaves and operators at the internal nodes. Postfix is that tree’s postorder (left, right, node). Fully bracketed infix is its inorder (left, node, right) with a ( before and a ) after every internal node. The conversion reads one traversal and writes the other.
Approach 1: Stack of strings
Intuition. Postfix is built for stack evaluation: scanning left to right, every operator applies to the two most recent complete values. Here the “values” are strings that already hold the infix form of a sub-expression. An operand is a complete sub-expression by itself. When an operator arrives, pop its two operands and push the combined string "(" + left + op + right + ")". At the end, one string remains, and it is the whole expression.
Order matters. The right operand was completed last, so it is on top. The first pop is the right operand and the second is the left operand.
The brackets are what make this correct without a precedence table. Each combined string is a closed unit, so when it later becomes an operand of another operator, its internal structure cannot be misread.
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 push"(" + left + c + right + ")".
- If
- Return the single remaining string (
""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("(" + left + c + right + ")");
}
}
return st.isEmpty() ? "" : st.pop();
}
Dry run on "ab*c+":
| char | action | stack (bottom to top) |
|---|---|---|
| a | push | a |
| b | push | a, b |
| * | pop b, pop a, push (a*b) |
(a*b) |
| c | push | (a*b), c |
| + | pop c, pop (a*b), push ((a*b)+c) |
((a*b)+c) |
Complexity. Time O(n^2) in the worst case. There are O(n) stack operations, but each concatenation copies both operands. A left-leaning chain like aa+a+a+... builds strings of length 5, 9, 13, …, and copying all of them is quadratic in n. Space O(n) for the stack and the strings on it.
This is the answer most people give in an interview and it is fine for inputs of a few thousand characters.
Approach 2: Optimal, expression tree and one bracketed inorder walk
Intuition. The quadratic cost comes from repeatedly copying the same characters each time a sub-expression gets wrapped by another operator. So postpone writing text until the structure is complete. Run the same stack scan, but push tree nodes: a leaf for each operand, and for each operator a new node whose children are the two popped nodes. Building a node is O(1) regardless of how big its subtrees are.
When the scan ends, the stack holds the root. A recursive inorder traversal then writes the answer straight into one StringBuilder: for a leaf, write its symbol; for an operator, write (, the left subtree, the operator, the right subtree, and ). Each node is visited once and each output character is written once.
Algorithm.
- If the input is empty, return
"". - Scan left to right with a stack of nodes. Operand: push a leaf. Operator: pop
right, popleft, pushnew Node(op, left, right). - Call
inorder(root, out)and returnout.
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, then write a bracketed inorder traversal into one StringBuilder. 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();
inorder(st.pop(), out);
return out.toString();
}
static void inorder(Node node, StringBuilder out) {
if (node.left == null) { // a leaf is an operand
out.append(node.symbol);
return;
}
out.append('(');
inorder(node.left, out);
out.append(node.symbol);
inorder(node.right, out);
out.append(')');
}
Why it produces the same string as Approach 1. By induction on the tree: a leaf produces its own character in both methods. For an operator node, Approach 1 produces "(" + L + op + R + ")" where L and R are the strings for the subtrees, and inorder writes (, then whatever the left subtree writes, then op, then the right subtree, then ), which is the same sequence of characters.
Complexity. Time O(n): n nodes are created and each is visited once; the output has length at most n + 2 × (number of operators), which is under 2n. Space O(n) for the nodes, plus recursion depth equal to the tree height. A left-leaning chain has height about n / 2, so for very long degenerate inputs an iterative traversal (with an explicit stack of pending actions) would be safer; the test file exercises a chain of 1000 operators.
Edge cases and pitfalls
- Pop order. In a left-to-right scan the first pop is the right operand. Reversing them turns
a-bintob-a. Use-,/or^in tests;+and*hide this bug. - Single operand.
"a"returns"a", not"(a)". Brackets are only added around an operator and its operands. - Empty input. Both methods return
""rather than popping an empty stack. - Minimal brackets. Some variants want
a*b+cinstead of((a*b)+c). That needs precedence: wrap a child in brackets only if its operator binds looser than the parent’s operator, or binds equally and sits on the side that associativity does not favour (the right child of a left-associative operator such as+ - * /, the left child of the right-associative^). Check which output format your judge expects. - Invalid input. Both methods assume a valid expression. A stack with fewer than two items at an operator, or more than one item at the end, means the input was malformed.
- Multi-character operands. Tokenize first; nothing else changes.
Related problems
- Prefix to Infix Conversion is the same bracketing idea for prefix input, scanned from the right.
- Postfix to Prefix Conversion uses this exact scan and tree, but writes a preorder instead.
- Prefix to Postfix Conversion converts between the two bracket-free notations.
- Infix to Postfix Conversion is the reverse direction, where precedence must be handled explicitly.
- Balanced Paranthesis checks that bracket pairs, like the ones produced here, are properly nested.