今天数据结构上机遇到了这道题,写完了,记录一下。
参考了大神的博客:链接,主要是看了他的思想,实现完全是自己写的,这里说说实现思想吧:
前提:求解需要两个栈,一个存操作数,一个存符号。
中心思想:遇到符号保证栈顶优先级小于此符号,满足后将其push到符号栈中处理完符号栈即可。
1、对于数字,直接push,我处理数字的方法是遇到数字直接把数字一位一位的放到一个string里,然后转换成数字。
还有负数的处理,需要在遇到符号时判断,符号前面是
或者是负号是表达式的第一位的话就是负数的标志。
2、对于左括号,直接push到符号栈。
3、对于右括号,处理符号栈中符号,直到遇到左括号。
4、对于加减,需要处理到( 左括号。
5、对于乘除,处理到+ - 或( 左括号
6、对于负数,判断是负数之后设一个flag,把转换出来的数字直接乘-1即可。
遵循这个规则,处理到符号栈空即可。
程序注释很详细,看程序就能看懂。
#include <iostream>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
double cal(char oper,double lv,double rv){//计算函数
if(oper=='+'){
return lv+rv;
}
else if(oper=='-'){//lv对应第一个出栈的数,是右值
return rv-lv; //对于+*无所谓 /-就得反过来
}
else if(oper=='*'){
return lv*rv;
}
else{
if(lv==0){//除零就结束程序
cout<<"divide by zero"<<endl;
exit(0);
}
return rv/lv;
}
}
bool isok(char in){//检验符号函数
if(in>='0'&&in<='9'){
return true;
}
else if(in=='.'||in=='+'||in=='-'||in=='*'||in=='/'||in=='('||in==')'){
return true;
}
else{
return false;
}
}
int main(){
stack<char> oper;//符号栈
stack<double> ans;//运算数栈
string exp;//表达式字符串
cin>>exp;
int len=(int)exp.length();
int i=0;
for(i=0;i<len;i++){//先查一遍表达式
if(isok(exp[i])==false){
cout<<"Expression invalid!"<<endl;
exit(0);
}
}
i=0;
while(i<len){//扫描一遍表达式
double num=0;//操作的数
int flag=0;//负数标志
string temp;//临时字符串以便转换数字
if(exp[i]=='-'){//要点!! 处理负数情况
if(exp[i-1]=='('||exp[i-1]=='+'||exp[i-1]=='-'||exp[i-1]=='*'||exp[i-1]=='/'){//说明这个负号是负数开头的标志
i++; //符号后面必定是数字i++直接可以扫描数字而不用多一些判断
flag=1;
}
if(i==0){//开头的负号必定是负数标志
i++;
flag=1;
}
}
if(exp[i]>='0'&&exp[i]<='9'){//若是数字
while((exp[i]>='0'&&exp[i]<='9')||exp[i]=='.'){
temp.append({exp[i]});//在字符串里加入数字
i++;
}
i--;//这是因为while最后还有一个i++这样就不会跳过去一个了
num=stod(temp)*(flag==1? -1:1);//若转换出错,就会结束程序
ans.push(num);//将数字push到运算数栈中
}
if(exp[i]=='+'||exp[i]=='-'){
if(oper.size()==0){//运算符栈为空就直接push
oper.push(exp[i]);
}
else{
while(oper.size()&&oper.top()!='('){//对于加减需要保证栈顶是'('才能入栈
double l=ans.top();//得到第一个运算数->右值
ans.pop();
double r=ans.top();//得到第二个运算数->左值
ans.pop();
ans.push(cal(oper.top(), l, r));//放到计算函数计算
oper.pop();//pop掉运算符
}
oper.push(exp[i]);//push当前的运算符
}
}
if(exp[i]=='*'||exp[i]=='/'){
if(oper.size()==0){//运算符栈为空直接push
oper.push(exp[i]);
}
else{
while(oper.size()&&oper.top()!='+'&&oper.top()!='-'&&oper.top()!='('){
double l=ans.top();//同+-的情况,但是乘除的优先级更高
ans.pop();
double r=ans.top();
ans.pop();
ans.push(cal(oper.top(), l, r));
oper.pop();
}
oper.push(exp[i]);
}
}
if(exp[i]=='('){//左括号直接push
oper.push(exp[i]);
}
if(exp[i]==')'){//右括号处理到左括号
while(oper.size()&&oper.top()!='('){
double l=ans.top();//运算和+-*/相同
ans.pop();
double r=ans.top();
ans.pop();
ans.push(cal(oper.top(), l, r));
oper.pop();
}
oper.pop();
}
i++;
}
if(oper.size()){//处理符号栈剩余的
while(oper.size()){//不同判断 全部处理
double l=ans.top();
ans.pop();
double r=ans.top();
ans.pop();
ans.push(cal(oper.top(), l, r));
oper.pop();
}
}
printf("%lf\n",ans.top());//输出结果
return 0;
}