表达式求值
https://www.acwing.com/problem/content/3305/
首先进行中缀转后缀,然后根据后缀表达式求值。
转换过程:
准备一个符号栈,从左到右依次扫描中缀表达式
- 如果遇到数字,直接输出
- 若为
(
,直接入栈 - 若为
)
,依次出栈并输出,直到遇见(
,左括号出栈但不输出 - 若为
+
,-
,依次出栈并输出,直到遇见(
或栈空; - 若为
*
,/
,若栈顶为*
或/
,依次出栈并输出
求解过程:
准备一个数字栈,从左到右依次扫描后缀表达式
- 若为数字,直接压入栈中
- 若为操作符,取栈顶两个元素分别做相应运算,并将结果压入栈中(注意运算次序,先出栈的是第二个操作数,后出栈的是第一个操作数)
C++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
stack<char> stk;
stack<int> s;
// (2+2)*(1+1)
int main() {
string str; cin >> str;
string res;
for (int i = 0; i < str.length(); i ++) {
if (str[i] >= '0' && str[i] <= '9') {
do {
res += str[i ++];
} while(i < str.length() && str[i] >= '0' && str[i] <= '9');
if (i < str.length()) i --;
res += " ";
} else if (str[i] == '(') { // 入栈
stk.push('(');
} else if (str[i] == ')') { // 出栈
while(stk.top() != '(') {
res += stk.top();
res += " ";
stk.pop();
}
stk.pop();
} else if (str[i] == '+' || str[i] == '-') {
while(stk.size() && (stk.top() == '*' || stk.top() == '/' || stk.top() == '+' || stk.top() == '-')) { // + - * / 全部弹出
res += stk.top();
res += " ";
stk.pop();
}
stk.push(str[i]);
} else {
while(stk.size() && (stk.top() == '*' || stk.top() == '/')) { // * / 全部弹出
res += stk.top();
res += " ";
stk.pop();
}
stk.push(str[i]);
}
}
while(stk.size()) {
res += stk.top();
res += " ";
stk.pop();
}
// cout << res << endl;
for (int i = 0; i < res.length(); i ++) {
if (res[i] >= '0' && res[i] <= '9') {
int t = 0;
while(i < res.length() && res[i] != ' ') {
t = t * 10 + res[i ++] - '0';
}
s.push(t);
} else if (res[i] != ' ') {
int a1 = s.top(); s.pop();
int a2 = s.top(); s.pop();
if (res[i] == '+') {
s.push(a1 + a2);
} else if (res[i] == '-') {
s.push(a2 - a1);
} else if (res[i] == '*') {
s.push(a2 * a1);
} else {
s.push(a2 / a1);
}
}
}
cout << s.top() << endl;
return 0;
}
简洁做法
边转后缀边求值
根据遇到符号决定操作:
- 数字:读取数字并压入数字栈
- 左括号:压入符号栈
- 右括号:执行运算操作,直到符号栈遇到左括号,将左括号弹出
- 加减乘除:当前符号的优先级小于等于栈顶时,执行运算操作,将栈中能算的算完
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>
using namespace std;
stack<int>num;
stack<char>op;
void eval() {
int b = num.top(); num.pop();
int a = num.top(); num.pop();
char c = op.top(); op.pop();
int x;
if (c == '*') x = a * b;
else if (c == '/') x = a / b;
else if (c == '-') x = a - b;
else x = a + b;
num.push(x);
}
string str;
int main() {
cin >> str;
unordered_map<char, int> pr{{'-', 1}, {'+', 1}, {'*', 2}, {'/', 2}};
for (int i = 0; i < str.length(); i ++) {
auto c = str[i];
if (isdigit(c)) {
int d = 0, j = i;
while(j < str.length() && isdigit(str[j])) {
d = d * 10 + str[j ++] - '0';
}
num.push(d);
i = j - 1;
} else if (c == '(') op.push(c);
else if (c == ')') {
while(op.top() != '(') {
eval();
}
op.pop();
} else {
while(op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
cout << num.top() << endl;
return 0;
}