表达式求值

在刷栈相关的题目时碰到这样的一题:先附上链接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/

思路

核心想法有两个:

  1. 建立两个栈,一个运算符栈, 一个操作数栈。
  2. 建立运算符优先级表,以及规定入栈规则,以处理运算符优先级的问题。具体的规则如下:如果要入栈的运算符优先级比栈顶运算符优先级高,那么直接入栈,如果要入栈的运算符优先级小于或者等于栈顶运算符的优先级,那么先求值再入栈。

这么做的原因是,由于栈 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;
}
posted @ 2021-04-29 17:25  今天AC了吗  阅读(116)  评论(0)    收藏  举报