Implementing Infix Expression Evaluation Using a Stack Data Structure
Simple arithmetic expressions like 1 + 2 are straightforward to compute. However, evaluating more complex infix expressions such as 1 + (2 ^ 2) / 3 * 4 requires a systematic approach accounting for operator precedence and parentheses. A standard solution uses two stacks: one for numeric operands and another for operators.
The algorithm processes the expression string sequentially. When a number is encountered, it's pushed onto the operand stack. For operators, the system checks the operator stack. If empty, the new operator is pushed. If not empty, the precedence of the new operator is compared to the top of the operator stack. Based on precedence and associativity rules, operators are popped from the stack and applied to operands before pushing the new operator. Parentheses are handled specially: left parentheses are pushed onto the operator stack, and a right parenthesis triggers popping and calculation until a matching left parenthesis is found.
The following C++ implementation demonstrates this two-stack method.
#include <iostream>
#include <stack>
#include <cmath>
#include <cstring>
#include <cctype>
using namespace std;
stack<int> valueStack; // Holds numeric values
stack<char> symbolStack; // Holds operators and parentheses
// Executes an operation using the top operator from symbolStack
void evaluateOperator(char op) {
int rightOperand = valueStack.top();
valueStack.pop();
int leftOperand = valueStack.top();
valueStack.pop();
int computationResult = 0;
switch(op) {
case '+': computationResult = leftOperand + rightOperand; break;
case '-': computationResult = leftOperand - rightOperand; break;
case '*': computationResult = leftOperand * rightOperand; break;
case '/': computationResult = leftOperand / rightOperand; break;
case '^': computationResult = pow(leftOperand, rightOperand); break;
}
valueStack.push(computationResult);
}
int main() {
char expression[100];
cin.getline(expression, 100);
for (int pos = 0; pos < strlen(expression); ++pos) {
if (isdigit(expression[pos])) { // Handle multi-digit numbers
int currentNumber = 0;
while (pos < strlen(expression) && isdigit(expression[pos])) {
currentNumber = currentNumber * 10 + (expression[pos] - '0');
++pos;
}
--pos; // Adjust position after number parsing
valueStack.push(currentNumber);
}
else if (expression[pos] == '(') {
symbolStack.push('(');
}
else if (expression[pos] == ')') { // Evaluate until '(' is found
while (!symbolStack.empty() && symbolStack.top() != '(') {
evaluateOperator(symbolStack.top());
symbolStack.pop();
}
symbolStack.pop(); // Remove the '('
}
else if (strchr("+-*/^", expression[pos])) { // Handle operators
char currentOp = expression[pos];
// Determine precedence and evaluate higher/equal precedence ops
while (!symbolStack.empty() && symbolStack.top() != '(') {
char topOp = symbolStack.top();
bool shouldEvaluate = false;
// Define precedence: '^' > '/*' > '+-'
if ((currentOp == '+' || currentOp == '-') &&
(topOp == '+' || topOp == '-' || topOp == '*' || topOp == '/' || topOp == '^')) {
shouldEvaluate = true;
}
else if ((currentOp == '*' || currentOp == '/') &&
(topOp == '*' || topOp == '/' || topOp == '^')) {
shouldEvaluate = true;
}
else if (currentOp == '^' && topOp == '^') {
shouldEvaluate = true; // Right associativity for '^'
}
if (!shouldEvaluate) break;
evaluateOperator(topOp);
symbolStack.pop();
}
symbolStack.push(currentOp);
}
}
// Process any remaining operators
while (!symbolStack.empty()) {
evaluateOperator(symbolStack.top());
symbolStack.pop();
}
cout << valueStack.top() << endl;
return 0;
}
Python's eval() function offers a concise alternative by leveraging its built-in expression parser. The input string requires modification to use Python's exponent (**) and integer division (//) operators.
user_input = input()
modified_input = user_input.replace('^', '**').replace('/', '//')
print(eval(modified_input))
While Python porvides a succinct one-line solution, understanding the underlying stack-based algorithm is crucial for foundational computer science knowledge and implementing evaluators in environments without such built-in functions.