题目描述:
给定一个表达式,其中运算符仅包含 +,-,*,/
(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
注意:
- 数据保证给定的表达式合法。
- 题目保证符号
-
只作为减号出现,不会作为负号出现,例如,-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;
}