表达式计算就是给你一个含有加减乘除的表达式,让你计算出结果。
题目: 来自AcWing打卡活动
类似的题型咱们见过很多,但是这个是涉及最全面的题,不光含有加减乘除,还有次方以及括号,那么这个题就难度上去了。
优先级
首先说一下思路,就是用两个栈,一个栈用来存数值,另一个用来存运算符,在计算之前要梳理好运算符的计算顺序,^ > (* /) > (+ -),当然括号是特殊的。
整体思路
比如1+2*3+2. 首先把数值放入栈,‘+’进栈,2进栈,到 ‘ * ’ 的时候先判断前面的可不可以合并,因为乘号优先级高,那么就先不合并,‘ * ’ 进栈 ,3进栈,到‘ +’ 的时候,因为前面的乘号优先级高,所以3,2出栈,‘ * ’ 出栈,结果6进栈,然后 ‘ + ’ 不必当前符号优先级高,那么1,6出栈,7进栈,‘ + ’ 出栈。然后2进栈,2,7出栈,9进栈,当所有数走完的时候,数值的栈顶就是结果。
这是一个简单的样例模拟先把这个过程搞明白,当然还会有很多特殊情况。
括号的影响
因为题上说了括号不一定是一一对应的,但是肯定合法,首先现在最后放一个右括号,然后,为了防止右括号多出来对结果影响。咱们在左边加一定数量的左括号,跟可能多出来的右括号匹配。为了防止左括号多出来影响结果,咱们可以在最后一个字符计算结束的时候判断数值的栈长度是否为1,如果不为1,说明还没计算结束,那么讲下标减一,再遍历一次最后一个字符(右括号)。直到数值栈的长度为1,数值栈顶的数就是答案。
负数的处理
在处理负数的时候,首先要确定是负号还是减号,如果该符号的上一个符号不是数值而且不是右括号就说明该符号是负号,那么就把这个负号变成-1放入数值栈,在符号栈里面放入一个’ *‘ ,之后就可以进行之后的操作了。
明白以上特殊情况之后就可以码代码了,思路虽然搞明白了,但是这一个代码的实现还是非常考验功底的。
#include<iostream>
#include<algorithm>
#include<stack>
#include<string>
using namespace std;
stack<int>yi;
stack<char>er;
void cal()//用一个函数来实现栈内元素的计算。
{
int a = yi.top();yi.pop();//拿出 删除
int b = yi.top();yi.pop();//拿出 删除
char s = er.top();er.pop();//拿出 删除
int d;
if(s=='+')
d=a+b;
else if(s=='-')
d=b-a;
else if(s=='*')
d=b*a;
else if(s=='/')
d=b/a;
else if(s=='^')
{
d=1;
while(a--) d*=b;
}
yi.push(d);//结果需要入栈
}
int main(void)
{
string str,x;
cin >> str;
for(int i=0; i<str.size(); i++) x+="(";
str=x+str+')';//加左括号和右括号。
int sum;
for(int i=0; i<str.size(); i++)
{
if(isdigit(str[i]))//是数字
{
sum=0;//用下面的循环直接将整个数读入
while(isdigit(str[i])) sum=sum*10+str[i]-'0',i++;
yi.push(sum);//整数入栈
i--;//因为出循环的时候还会 i++。当前的位置就是下一个要操作的位置,所以减一。
}
else//对应符号进行操作。
{
char s = str[i];
if(s=='+'||s=='-')
{
if(s=='-' && !isdigit(str[i-1])&&str[i-1]!=')')//处理负号
{
sum=0;
yi.push(-1);
er.push('*');
}
else
{
while(er.top()!='(') cal();//只要前面那个不比自己优先级低就一直计算
er.push(s);//当前符号入栈
}
}
else if(s=='*'||s=='/')
{
while(er.top()=='*'||er.top()=='/'||er.top()=='^') cal();//只要前面那个不比自己优先级低就一直计算
er.push(s);//当前符号入栈
}
else if(s=='^')
{
while(er.top()=='^') cal();//只要前面那个不比自己优先级低就一直计算
er.push(s);///当前符号入栈
}
else if(s==')')//右括号的话,则一直计算到对应的左括号
{
while(er.top()!='(') cal();
er.pop();//弄完之后删除左括号。
}
else if(s=='(') er.push(s);//如果是左括号,则直接入栈就行。
}
if(i ==str.size()-1 && yi.size()!=1) i--;//如果在最后的时候,数值栈内不只有一个数,那么则一直计算到剩下一个数值。
}
cout<<yi.top()<<endl;//栈顶就是结果。
return 0;
}
这个代码如果搞懂了,之后所有的类似表达式的题都是可以的,这个基本上是最全的了。