题目:
给定一个表达式,其中运算符仅包含 +,-,*,/
(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
注意:
- 数据保证给定的表达式合法。
- 题目保证符号
-
只作为减号出现,不会作为负号出现,例如,-1+2
,(2+2)*(-(1+1)+2)
之类表达式均不会出现。 - 题目保证表达式中所有数字均为正整数。
- 题目保证表达式在中间计算过程以及结果中,均不超过 2^31-1。
- 题目中的整除是指向 0 取整,也就是说对于大于 00 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。
- C++和Java中的整除默认是向零取整;Python中的整除
//
默认向下取整,因此Python的eval()
函数中的整除也是向下取整,在本题中不能直接使用。
输入格式
共一行,为给定表达式。
输出格式
共一行,为表达式的结果。
数据范围
表达式的长度不超过 105105。
输入样例:
(2+2)*(1+1)
输出样例:
8
涉及知识点:
一.栈(stack),是STL中实现先进后出的容器。
头文件:include<stack>
定义:stack<typename>name;
例如:stack<int>st;
st.push(i); //将i压入栈
a=st.top(); //取栈顶元素
st.pop(); //取出栈顶元素
st.size(); //返回栈内元素个数
二.unordered_map/map
unordered_map是一个关联容器,它将键值存储在哈希表中,可以快速地查找和访问元素。
每个关键字(key)只能在unordered_map/map中出现一次;关键字的值(value)可以重复。该容器能够建立关键字与值之前的映射关系(比如建立字符/字符串与整数之间的映射关系)
与map相比,unordered_map的插入、删除和查找操作都更快,但是它的元素是无序的(所以对于一些有顺序要求的问题,用map;对于查找问题,考虑用unordered_map)
map的使用(unordered_map相似):
1.头文件:#include<map>
2.定义 map<int,string> student;
3.初始化 map<int,string> student={{1,xiaohong},{2,xiaobai}};
4.赋值 student[5]="lisi";
//使用[]进行单个插入,若已经存在key值5,则赋值被修改,若无则插入
//key值作为下标,它可以是任意类型
三.前缀表达式、中缀表达式和后缀表达式
1.前缀表达式(也称为波兰式)是一种没有括号的算术表达式,其运算符写在前面,操作数写在后面。如 -1+2 3 <=>1-(2+3)
2.中缀表达式即人们常用的算术表示方法
3.后缀表达式(也称为逆波兰式)运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,更便于计算机运算(该题目实际上是将中缀表达时转化成后缀表达式进而运算)
思路:
一.建立双栈,一个操作数栈,一个运算符栈
二.从左到右扫描中缀表达式中的每个元素(分四种情况讨论)
1.若当前元素是数字,那么计算出操作数并将其压入操作数栈
2.若当前元素是左括号,则直接将左括号压入运算符栈
3.若当前元素是右括号,则计算栈中的元素直到遇到左括号为止;计算完毕后,右括号不压入栈中,并且将左括号弹出
4.若当前元素是+ - * / 运算符,那么将与栈顶运算符的优先级进行比较。若栈顶运算符优先级高于或等于当前运算符优先级,将栈顶运算符弹出并进行运算。重复该步骤,直到栈顶运算符优先级小于当前运算符优先级,再把当前运算符压入栈中。
三.若扫描完中缀表达式后,栈中仍存有元素,则依次运算
在纸上模拟过程如下:(1+2)*3+4
代码实现如下:
#include<iostream>
#include<stack>
#include<string>
#include<unordered_map>
using namespace std;
stack<int> num;//操作数栈
stack<char> op; //运算符栈
unordered_map<char,int> h{{'+',1},{'-',1},{'*',2},{'/',2}};//运算符优先级
//取栈顶运算符x1 栈顶操作数x2
void eval(){
int a=num.top();num.pop();
int b=num.top();num.pop();
char c=op.top();op.pop();
int r;
if(c=='+')r=b+a;
if(c=='-')r=b-a;
if(c=='*')r=b*a;
if(c=='/')r=b/a;
num.push(r);
}
int main(){
string s;
cin>>s;
//遍历中缀表达式
for(int i=0;i<s.size();i++){
//若s[i]为数
if(isdigit(s[i])){
int x=0; //x为操作数
while(isdigit(s[i])){
x=x*10+s[i++]-'0';
}
num.push(x);
i--;
}
//若s[i]为左括号,则直接压入运算符栈(左括号无优先级)
else if(s[i]=='(')op.push(s[i]);
//若s[i]为右括号,则从右往左计算,直到遇到左括号
else if(s[i]==')'){
while(op.top()!='(')eval();
op.pop();//弹出左括号
}
//若s[i]为+-*/运算符
//栈顶运算符优先级大于等于新运算符时,先将栈顶运算符取出进行运算,再将新运算符压入栈
else{
while(op.size()!=0&&h[op.top()]>=h[s[i]])eval();
//一定要记得判断运算符栈不为空
op.push(s[i]);
}
}
while(op.size())eval();(不能用判断语句!)
cout<<num.top()<<endl;
return 0;
}