表达式求值
在刷栈相关的题目时碰到这样的一题:先附上链接https://www.acwing.com/problem/content/description/3305/
表达式求值
题目是给定一个表达式,其中运算符仅包含 +,-,,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
其中:
数据保证给定的表达式合法。
题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)(-(1+1)+2) 之类表达式均不会出现。
题目保证表达式中所有数字均为正整数。
题目保证表达式在中间计算过程以及结果中,均不超过 231−1。
题目中的整除是指向 0 取整,也就是说对于大于 0 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。
刚开始我写了好久,通过一些乱七八糟的办法来处理优先级和括号,在尝试很久仍然有几个点无法AC之后求助了题解区,看到这篇题解的解答感觉豁然开朗。
https://www.acwing.com/solution/content/40978/
思路
核心想法有两个:
- 建立两个栈,一个运算符栈, 一个操作数栈。
- 建立运算符优先级表,以及规定入栈规则,以处理运算符优先级的问题。具体的规则如下:如果要入栈的运算符优先级比栈顶运算符优先级高,那么直接入栈,如果要入栈的运算符优先级小于或者等于栈顶运算符的优先级,那么先求值再入栈。
这么做的原因是,由于栈 Last in First out 的特性,晚入栈的运算符会先被处理,对于优先级高的运算符,我们应该先处理它,所以可以直接入栈,而对于优先级低的运算符,我们如果还直接入栈,处理的时候就会导致它再优先级比它高的运算符之前被处理,这是不符合运算规则的。
因此,我们读入表达式字符串之后,逐个字符处理,若碰到数字,我们把整个数字读进来,push 进操作数栈,对于左括号,我们直接入栈,对于又括号,我们把左括号之后的运算都处理掉,然后把左括号也出栈,对于运算符,则按照上述的规则操作。最后,再把剩余的运算都算掉,剩下的栈顶就是答案。
AC代码
#include <iostream>
#include <stack>
#include <unordered_map>
using namespace std;
stack<int> operands;
stack<char> operators;
unordered_map<char,int> op_map{{'+',1},{'-',1},{'*',2},{'/',2}};//运算符优先级表
void eval(){//求值操作
int n2 = operands.top();
operands.pop();
int n1 = operands.top();
operands.pop();
char tt = operators.top();
operators.pop();
if(tt == '+')operands.push(n1+n2);
else if(tt == '-')operands.push(n1-n2);
else if(tt == '*')operands.push(n1*n2);
else operands.push(n1/n2);
}
int main(){
string s;
string num;
int i = 0;
cin>>s;
while(i<s.size()){
if(s[i]>='0' && s[i]<='9'){//读入操作数
while(i < s.size() && s[i] >= '0' && s[i] <= '9'){
num += s[i];
i++;
}
operands.push(stoi(num));
num = "";
}else if(s[i] == '('){
operators.push(s[i]);
i++;
}else if(s[i] == ')'){//一口气处理完括号里面的运算
while(operators.top() != '(') eval();
operators.pop();
i ++;
}else{//按照优先级入栈,高优先级算符直接入栈,低优先级算符先求值后入栈
while(operators.size() && op_map[s[i]]<=op_map[operators.top()]){
eval();
}
operators.push(s[i]);
i++;
}
}
//处理剩下的所有算符
while(operators.size())eval();
cout<<operands.top()<<endl;
return 0;
}

浙公网安备 33010602011771号