C++ 后缀表达式转为中缀表达式,并计算结果

版权声明:作者:weizu_cool https://blog.csdn.net/qq_26460841/article/details/88529548

2、输入表达式,输出值。分两种情况:中缀表达式和后缀表达式。

中缀表达式求值:先将中缀表达式建立二叉树转后缀表达式,然后再求值。

尝试1:

#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>//sum1=atof(t1.c_str());
using namespace std;
 

//后缀表达式求值,这种方式的弊端很明显,只能计算单个位置的数据,不能出现多位数和小数,原因是我这里每次取数是expression[i]造成的 
double  postfix_expression(string expression){
	//56+2*3+
	double stack[20];//操作数栈
	int top = -1;//栈顶指针
	for(int i=0;i<expression.length();i++){
		if(expression[i]=='+'){
			double d = stack[top];//栈顶指针在top 
			top--;
			double c = stack[top];
			stack[top]=d+c;
			cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
		}else if(expression[i]=='-'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c-d;
			cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
		}else if(expression[i]=='*'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c*d;
			cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
		}else if(expression[i]=='/'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c/d;
			cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
		}else if(expression[i]>='0' and expression[i]<='9'){
			top++;
			string s = expression.substr(i,1);
			double c = atof(s.c_str());
			stack[top]=c;
		}else{
			cout<<"输入错误!"<<endl;
			exit(0);
		}
	} 
	return stack[top--];
}
int main()
{
//	string ex;
//	cout<<"请输入后缀表达式:"; 
//	cin>>ex;
	//用例:3*(5+4)/8+4*(5+2) 
    cout<<postfix_expression("54+3*8/52+4*+")<<endl;
    return 0;
}

猜想,我们对数字的判断应该在之前就判断完毕,因为后缀表达式中,如:54+3*8/52+4*+,是比较难确定54还是5 4 当然可以用操作符的个数匹配,但是比较麻烦。这里,我们可以用中缀表达式,也就是原来输入的数据表达式,然后我们截取数据放入集合中,集合的类型是vector<string>,我们在使用后缀表达式的时候,转换数据就会比较方便。下面关键是如何处理由中缀表达式向后缀表达式转化。

参考数据结构:

需要用操作符的优先级进行栈运算。用icp(in coming priority)表示当前扫描到的运算符的优先级,用isp(in stack priority)表示该运算符进栈后的优先级。

操作符

#

(

* /

+ -

)

isp

0

1

5

3

6

icp

0

6

4

2

1

举例说明:3*(5+4)/8+4*(5+2)

中缀表达式:3*(5+4)/8+4*(5+2)  后缀表达式:354+*8/452+*+

步骤

扫描项

项类型

动作

字符栈内内容

输出

0

‘#’进栈,读取下一字符

#

1

3

操作数

直接输出

#

3

2

*

操作符

isp(#)<icp(*),进栈

#*

3

(

操作符

isp(*)<icp((),进栈

#*(

4

5

操作数

直接输出

#*(

5

5

+

操作符

isp(()<icp(+),进栈

#*(+

6

4

操作数

直接输出

4

7

)

操作符

isp(+)>icp()),出栈

#*(

+

isp(()==icp()),退栈

#*

8

/

操作符

isp(*)>icp(/),出栈

#

*

isp(#)<icp(/),出栈

#/

9

8

操作数

直接输出

8

10

+

操作符

isp(/)>icp(+),出栈

#

/

11

isp(#)<icp(+),进栈

#+

12

4

操作数

直接输出

4

13

*

操作符

isp(+)<icp(*),进栈

#+*

14

(

操作符

isp(*)<icp((),进栈

#+*(

15

5

操作数

直接输出

5

16

+

操作符

isp(()<icp(+),进栈

#+*(+

17

2

操作数

直接输出

2

18

)

操作符

isp(+)>icp()),出栈

#+*(

+

isp(()==icp()),退栈

#+*

19

#

操作符

isp(*)>icp(#),出栈

#+

*

isp(+)>icp(#),出栈

#

+

isp(#)==icp(#),退栈结束

#)

就可以得到中缀表达式,所以这里需要使用优先级比较+栈

#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <cstdlib>//sum1=atof(t1.c_str());
using namespace std;
 
/*
操作符	#	(	* /	 + -	)
isp	   0	1	5	 3 	   6
icp	   0	6	4	 2 	   1
*/
//四则运算,栈内>入栈,而且*/一定高于+-;括号,栈内<入栈, 站内尾大,入栈头大,占两端 
// 前期思考数据封装函数,最后演化成 transform_postfix 中的中心架构 
vector<double> data_package(string expression){
	vector<double> vc;
	int index=0, count=0;//记录需要截取字符串的下标位置
	for(int i=0;i<expression.length();i++){
		//3*(5+4)/8+4*(5+2)
		if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]=='('){
			if(count!=0){
				string s=expression.substr(index, count);//使用截取而不是直接expression[i],是因为写入字符,是字符地址后面的一大坨字符(首地址) 
				double num = atof(s.c_str());
				vc.push_back(num);
			}
			index=i+1;
			count=0;
		}
		else {
			count++;
		}
	} 
	return vc;
}
//3*(5+4)/8+4*(5+2)
//为了方便+-*/()表示为:335516   224461
int get_isp(char a){
	if(a=='+' or a=='-')
		return 3;
	else if(a=='*' or a=='/')
		return 5;
	else if(a=='(') 
		return 1;
	else if(a==')')
		return 6;
	else if(a=='#')
		return 0;
}
int get_icp(char a){
	if(a=='+' or a=='-')
		return 2;
	else if(a=='*' or a=='/')
		return 4;
	else if(a=='(') 
		return 6;
	else if(a==')')
		return 1;
	else if(a=='#')
		return 0;
}
string transform_op_stack_to_string(char a){
	//op_stack[top]
	if(a=='+')
		return "+";
	else if(a=='-')
		return "-";
	else if(a=='*')
		return "*";
	else if(a=='/')
		return "/";
}
//思路来源于上面的:data_package 
string  transform_postfix(string expression){
	//这里也要完成表达式的封装vector<string>
	vector<double> vc = data_package(expression);
	char op_stack[20];//+-*/():335516   224461
	int top = -1;
	top++;
	op_stack[top]='#';
	string str="";
	int index=0, count=0;//记录需要截取字符串的下标位置
	int i=0;
	while(top!=-1){
		if(i==expression.length()){
			expression.append("#");//因为栈可能没出完,而表达式判断已经到了末尾 
		}
		if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]=='#' or expression[i]=='('){
			//数字在前 
			if(count!=0){
				string s=expression.substr(index, count);
				str.append(s);
				str.append(" ");  //数字,直接输出 
			}
			index=i+1;
			count=0;
			
			//符号判断在后 
			//isp icp 大,进;小,顶出;等,退 
			if(get_isp(op_stack[top])<get_icp(expression[i])){
				top++;
				op_stack[top]=expression[i]; 
			}else if(get_isp(op_stack[top])>get_icp(expression[i])){
				bool flag = true;//是否循环 
				while(flag){//使用标识,进栈或者退栈,就退出循环 
					if(get_isp(op_stack[top])>get_icp(expression[i])){
						//小 ,顶出
						str.append(transform_op_stack_to_string(op_stack[top])+" ");
						//这里之所以要把char 转为 string ,是因为使用char 数组,加入的是该地址后的所有的字符 
					//	cout<<op_stack[top]<<"顶出"<<"此时的比较元素是:"<<expression[i]<<endl;
						top--; 
					}else if(get_isp(op_stack[top])<get_icp(expression[i])){//大,进 
						top++;
						op_stack[top]=expression[i]; 
						flag = false;//不再循环 
					//	cout<<op_stack[top]<<"进栈"<<endl;
					}else if(get_isp(op_stack[top])==get_icp(expression[i])){
						flag = false;//不再循环 
					//	cout<<op_stack[top]<<"退栈"<<endl;
						top--;//等,退 
					} 
				}
			}else if(get_isp(op_stack[top])==get_icp(expression[i])){
				top--;//等,退 
			} 
		}else {
			count++;
		}
		i++;
	}
	cout<<"后缀表达式的结果:"<<str<<endl;
	return str;
}



//初始版本(已抛弃):后缀表达式求值,这种方式的弊端很明显,只能计算单个位置的数据,不能出现多位数和小数,原因是我这里每次取数是expression[i]造成的 
double  postfix_expression(string expression){
	//56+2*3+
	double stack[20];//操作数栈
	int top = -1;//栈顶指针
	cout<<"计算的过程如下:"<<endl; 
	for(int i=0;i<expression.length();i++){
		if(expression[i]=='+'){
			double d = stack[top];//栈顶指针在top 
			top--;
			double c = stack[top];
			stack[top]=d+c;
			cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
		}else if(expression[i]=='-'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c-d;
			cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
		}else if(expression[i]=='*'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c*d;
			cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
		}else if(expression[i]=='/'){
			double d = stack[top];
			top--;
			double c = stack[top];
			stack[top]=c/d;
			cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
		}else if(expression[i]>='0' and expression[i]<='9'){
			top++;
			string s = expression.substr(i,1);
			double c = atof(s.c_str());
			stack[top]=c;
		}else{
			cout<<"输入错误!"<<endl;
			exit(0);
		}
	} 
	return stack[top--];
}
//改进
double  postfix_expression_fix(string expression){
	//56+2*3+
	double stack[20];//操作数栈
	int top = -1;//栈顶指针
	int count=0, index=0; 
	//测试的结果:3 5 4 + * 8 / 4 5 2 + * +  用空格分割 
	for(int i=0;i<expression.length();i++){
		if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]==' ' or expression[i]=='('){
			//数字在前 
			if(count!=0){
				string s=expression.substr(index, count);
			//	cout<<"操作数:"<<s<<endl;//测试 
				top++;
				stack[top]=atof(s.c_str()); //字符串转化为double,加入栈 
			}
			index=i+1;
			count=0;
			
			//判断符号 
			if(expression[i]=='+'){
				double d = stack[top];//栈顶指针在top 
				top--;
				double c = stack[top];
				stack[top]=d+c;
				cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
			}else if(expression[i]=='-'){
				double d = stack[top];
				top--;
				double c = stack[top];
				stack[top]=c-d;
				cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
			}else if(expression[i]=='*'){
				double d = stack[top];
				top--;
				double c = stack[top];
				stack[top]=c*d;
				cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
			}else if(expression[i]=='/'){
				double d = stack[top];
				top--;
				double c = stack[top];
				stack[top]=c/d;
				cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
			}else if(expression[i]>='0' and expression[i]<='9'){
				top++;
				string s = expression.substr(i,1);
				double c = atof(s.c_str());
				stack[top]=c;
			}
		}else{
			count++;
		} 
		
	} 
	return stack[top--];
}
 
int main()
{
	string expression;
	cout<<"请输入中缀表达式:"; 
	cin>>expression;
	//用例:3*(5+4)/8+4*(5+2) 
	string postfix = transform_postfix(expression);//后缀表达式:354+*8/452+*+ 
	double result = postfix_expression_fix(postfix);
    cout<<"表达式:"<<expression<<",计算的结果是:"<<result<<endl;
    return 0;
}

下面是使用电脑计算器计算的结果: 

作者: 无涯明月

上篇: C++ STL deque(双向队列)

猜你喜欢

转载自blog.csdn.net/qq_26460841/article/details/88529548
今日推荐