用栈直接求中缀表达式的值--数据结构之栈的应用

今天数据结构上机遇到了这道题,写完了,记录一下。

参考了大神的博客:链接,主要是看了他的思想,实现完全是自己写的,这里说说实现思想吧:

前提:求解需要两个栈,一个存操作数,一个存符号。

中心思想:遇到符号保证栈顶优先级小于此符号,满足后将其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;
}

 

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值