Problem Description
Given an infix arithmetic expression containing single-digit operands, the operators '+' , '-' , '*' , '/' and parenthesis, construct any binary expression tree whose in-order traversal (ignoring parentheses) produces the original expression. The tree must respect the operator precedence (multiplication and division before addition and subtraction) and the evaluation rule that expressions within parentheses are computed first.
Key Insights
- Use a modified version of the Shunting Yard algorithm to respect operator precedence and associativity.
- Maintain two stacks: one for tree nodes (operands) and one for operators.
- When encountering an operator, build subtrees by popping from the operator stack if the current operator has lower or equal precedence than the operator at the top.
- Parentheses are used to temporarily override the natural precedence and must be handled separately.
- Finally, after processing the entire string, combine any remaining nodes in the stacks to build the complete tree.
Space and Time Complexity
Time Complexity: O(n) where n is the length of the expression, since we process each character once. Space Complexity: O(n) due to the stacks used to store nodes and operators.
Solution
We use two stacks to construct the expression tree:
- Operand Stack: Stores tree nodes (each with left and right child pointers).
- Operator Stack: Stores operators (and a special marker for '(').
As we scan the expression:
- If the current character is a digit, we create a new node and push it on the operand stack.
- If the character is an opening parenthesis '(', push it onto the operator stack.
- If it is a closing parenthesis ')', pop operators from the operator stack and combine nodes from the operand stack into subtrees until an opening parenthesis is encountered.
- For an operator, while the operator stack is not empty (and its top has higher or equal precedence compared to the current operator), pop the operator and create a subtree by popping two nodes from the operand stack (left operand and right operand). Push the formed subtree back into the operand stack. Then push the current operator onto the operator stack.
After processing the entire expression, merge any remaining operators with their respective operands from the stack to get the final binary expression tree.