AcWing 3302 表达式求值

题目描述:

给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。

注意:

  • 数据保证给定的表达式合法。
  • 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。
  • 题目保证表达式中所有数字均为正整数。
  • 题目保证表达式在中间计算过程以及结果中,均不超过 2^31−1。
  • 题目中的整除是指向 0 取整,也就是说对于大于 0 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。
  • C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。

输入格式

共一行,为给定表达式。

输出格式

共一行,为表达式的结果。

数据范围

表达式的长度不超过 10^5。

输入样例:

(2+2)*(1+1)

输出样例:

8

分析:

本题是一个简化版的中缀表达式求值,只有加减乘除这类常见的二元运算符,没有阶乘、乘方等一元运算符,也不含负号。题目保证表达式合法,所以,本题就是一道简单的模拟题了。

相信学过邓公讲的中缀表达式求值那节,都会对这题的思路记忆犹新。具体的思路可以参考第四章:栈与队列

求解中缀表达式,我们只需要维护一个操作符栈和一个操作数栈,从左到右扫描表达式。

扫到操作数就压入操作数栈中,当然,对于多位数,需要等到各位数都扫描完成才能入栈。

扫到操作符就和与操作符栈栈顶元素(若存在)比较优先级,栈顶运算符优先级较低则将当前运算符压入栈中,继续扫描;栈顶运算符优先级较高则出栈并将参与运算的运算数也出栈,计算后将运算结果压入栈中,同时继续比较当前运算符与栈顶运算符的优先级。
唯一的难点在于运算符优先级的比较上。比如说左括号,当它位于操作符栈顶时,优先级是低于其他运算符的,但是当扫描到的运算符是左括号时,它的优先级一般是高于栈顶运算符优先级的,也就是说,运算符的优先级要取决于它是在栈顶还是栈外。

从左往右扫描表达式时,如果操作符栈为空,那么不管扫描到什么运算符都入栈,如果扫到的运算符是(,则入栈,扫描到的运算符是+-时,一般优先级都是低于栈顶元素的优先级的,所以需要让栈顶元素出栈参与运算;扫描到*/时,如果栈顶元素是+或者-,乘除的优先级较高,就将*/入栈,继续扫描;扫描到)时,当栈顶元素不是(时,就不断地出栈运算,直到遇见(,就将(出栈,继续扫描。

需要注意的是,扫描表达式时,我们是扫描到数字和前面的数字拼接到一起,直到扫描到操作符,才将完整的操作数入栈,如果表达式的末尾是数字,那么在扫描完表达式后就需要继续将操作数入栈,继续运算。还有就是扫描完表达式时,操作符栈可能不止一种运算符,所以需要持续出栈运算直至栈空,比如2+2*3,就是在扫描完表达式才开始运算的。总的代码如下:

#include <iostream>
#include <stack>
#include <string>
using namespace std;
stack<int> num;
stack<char> op;
string s;
bool cmp(char c1,char c2) {
    if(c1 == '(' || c2 == '(')   return false;
    if(c1 == '+' || c1 == '-')  return true;
    if(c1 == '*' || c1 == '/') {
        if(c2 == '+' || c2 == '-')  return false;
        return true;
    }
}
void compute() {
    int a,b,res;
    a = num.top();
    num.pop();
    b = num.top();
    num.pop();
    char c = op.top();
    op.pop();
    if(c == '+')    res = a + b;
    else if(c == '-')   res = b - a;
    else if(c == '*')   res = a * b;
    else if(c == '/')   res = b / a;
    num.push(res);
}
int main() {
    cin>>s;
    int n = 0;
    for(int i = 0;i < s.size();i++) {
        if(isdigit(s[i])) {
            n = n * 10 + s[i] - '0';
        }
        else {
            if(i && isdigit(s[i-1])) {//操作数入栈
                num.push(n);
                n = 0;
            }
            if(s[i] == ')') {
                while(op.top() != '(') {
                    compute();
                }
                op.pop();
            }
            else {
                while(op.size() && cmp(s[i], op.top()))  compute();
                op.push(s[i]);
            }
        }
    }
    if(n)   num.push(n);//最后一个字符是数字
    while(op.size()) compute();
    cout<<num.top()<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值