题目描述
给定一个表达式,其中运算符仅包含 +
,-
,*
,/
(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
注意:
- 数据保证给定的表达式合法。
- 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,
-1+2,(2+2)*(-(1+1)+2)
之类表达式均不会出现。 - 题目保证表达式中所有数字均为正整数。
- 题目保证表达式在中间计算过程以及结果中,均不超过 2 31 − 1 2^{31}−1 231−1。
- 题目中的整除是指向 0 取整,也就是说对于大于 0 的结果向下取整,例如 5 / 3 = 1 5/3=1 5/3=1,对于小于 0 的结果向上取整,例如 5 / ( 1 − 4 ) = − 1 5/(1−4)=−1 5/(1−4)=−1。
- C++ 和 Java 中的整除默认是向零取整;Python 中的整除//默认向下取整,因此 Python 的 eval() 函数中的
*
整除也是向下取整,在本题中不能直接使用。
输入格式
共一行,为给定表达式。
输出格式
共一行,为表达式的结果。
数据范围
表达式的长度不超过 105 105 105。
输入样例:
(2+2)*(1+1)
输出样例:
8
代码&注释
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>
using namespace std;
const int N = 100010;
stack<char> op; // 定义字符栈
stack<int> num; // 定义数字栈
// 调用一次eval函数记为进行一次操作
void eval()
{
// 取出数字栈中的两个元素
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
// 取出符号栈中的元素
auto c = op.top(); op.pop();
// 根据符号进行相应的操作,并将结果压入栈中
if (c == '+') num.push(a + b);
else if (c == '-') num.push(a - b);
else if (c == '*') num.push(a * b);
else num.push(a / b);
}
int main()
{
string s;
cin >> s;
// 设置运算符的优先级,左右括号会单独处理
unordered_map<char, int> h = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
// 遍历表达式
for (int i = 0; i < s.size(); i ++)
{
char c = s[i];
// 提取出一个数字
if (isdigit(c))
{
int j = i;
int x = 0, r = 1;
while (j < s.size() && isdigit(s[j]))
{
x = (s[j] - '0') + x * 10;
j ++;
}
i = j - 1;
num.push(x);
}
// 遇到左括号直接压栈
else if (c == '(') op.push(c);
// 遇到右括号一直操作至遇到左括号,然后弹出左括号
else if (c == ')')
{
while (op.size() && op.top() != '(') eval();
op.pop();
}
// 遇到操作符 判断操作符的优先级,当前操作符优先级第则需要一直进行操作
else
{
while (op.size() && op.top() != '(' && h[op.top()] >= h[c]) eval();
op.push(c);
}
}
// 如果栈中还有操作符,则一直操作到得到运算结果
while (op.size()) eval();
// 数字栈顶元素即为最总运算结果
cout << num.top() << endl;
return 0;
}
小结
对表达式字符串的遍历即为进行表达式求值的主要过程。
算法实现思路
1.遍历到数字:把数字压入栈中
2.遍历到左括号:直接压入栈中
3.遍历到右括号:一直进行操作直到遇到左括号,然后把左括号弹出
4.遍历到运算符:判断当前运算符与字符栈顶中运算符的优先级。若当前运算优先级低,进行操作至栈顶运算符位左括号或者字符栈顶运算符优先级比自己低。
5.重读上述步骤直至遍历完毕
6.若字符栈中还有运算符,则运算至字符栈空