BJFU 基于栈的中缀算术表达式求值

本代码部分思路参照了博主(后面有提及)↓,原链接在下方

鬼減之刃

数据结构 基于栈的中缀算术表达式求值_fzyz2333的博客-CSDN博客_基于栈的中缀算术表达式求值

        博主只是个学生,发个帖子记录下自己的学习心得,这两天不知道为什么自己的Typora崩了几次险些丢失半学期的笔记觉得发到网上或许可以保存的更久。算是自己的学习总结,也不知道写的是不是很冗余,有问题欢迎指出。

        不多说了现在进入正题。


        本来以为这道题挺简单的,老师也大致讲了下思路,结果我利用课余碎片化的时间做了好久也没做出来,后面心态有点受影响加上很忙没有再去做,眼看着到ddl了,于是今天拿出一早上的时间去写,真的用了整整一早上才解决这一道题。

        只能说自己的基础太差了,还是缺少锻炼,感觉代码没有问题但是就是出不来正确的结果,最后一步一步调试才发现了一个一个的问题(第一次用调试,只能说。善于运用调试,真的是太香了)。

问题总结:

        1、一开始甚至想将运算符和操作数栈用一个结构体实现,至少在现在的我看来是不能的,这就导致我用 atof 函数转变后虽然得到了正确的浮点型数字,但是却存入了数据类型为char 的OPND栈,而且转化为浮点型的数据也只能存进去一个。

        2、函数类型名全起了 int ,导致 return 无法返回正确的数据类型。

        3、循环结束条件写的太混乱导致自己也懵了,多次陷入死循环,好在后面调试时理清了思路。

        4、到底是用char 还是 string 分不清楚,试了试 atof 函数,发现char * 才管用。而这里参照了上面那位博主的代码使用字符数组,我想atof(数组名)也管用应该是数组名z本身就是个地址,maybe,c语言没好好学(捂脸)。

        5、用char 类型的话,对于两位数以上的运算数,怎么把它存放到栈的一个数据中?比如4.5,用char 一个一个输入,先识别到了4,如果压栈,那么0.5怎么办?这里就参照了博主的方法,先把识别到的数字存到到一个字符数组里,一直存到这个数后面的字符是运算符了,那么这个数组里存的内容就是一个运算数了,再进行atof操作,把结果压入OPND栈。

        问题基本都是通过“调试”一步一步发现的!再说一遍,调试!真的!太!香!了!!!


        总的来说我觉得这一早上挺值得的,确实感觉收获颇丰。

        现在附上修改过的原码吧。(BJFU的uu不要直接cv哦,防止查重,有问题我们可以交流!)

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<iomanip>
using namespace std;

#define MAXSIZE 1000

#define OK 1
#define ERROR 0
#define OVERFLOW -2

// 将优先级次序存储到二维数组 
char precede[7][7] = {
		'>','>','<','<','<','>','>',
		'>','>','<','<','<','>','>',
		'>','>','>','>','<','>','>',
		'>','>','>','>','<','>','>',
		'<','<','<','<','<','=','x',
		'>','>','>','>','x','>','>',
		'<','<','<','<','<','x','='
	};

// 定义用于存放运算符的OPTR栈类型 
typedef struct{
	char *top;
	char *base;
	int stacksize;
}SqStack;

// 定义用于存放操作数的OPND栈类型 
typedef struct{
	double *top;
	double *base;
	int stacksize;
}SqStackd;

// 对于栈类型的初始化、出栈、入栈、取栈顶操作定义 
int InitStack(SqStack &S){
	S.base = new char[MAXSIZE];
	if(!S.base) exit(OVERFLOW);
	S.top = S.base;
	S.stacksize = MAXSIZE;
	return OK;
}

char Push(SqStack &S,char e){
	if(S.top - S.base == S.stacksize) return ERROR;
	*S.top++ = e;
	return OK;
}

char Pop(SqStack &S){
	if(S.top == S.base) return ERROR;
	return *--S.top;
}

char GetTop(SqStack S){
	if(S.top == S.base) return ERROR;
	return *(S.top - 1);
}

int InitStackd(SqStackd &S){
	S.base = new double[MAXSIZE];
	if(!S.base) exit(OVERFLOW);
	S.top = S.base;
	S.stacksize = MAXSIZE;
	return OK;
}

double Pushd(SqStackd &S,double e){
	if(S.top - S.base == S.stacksize) return ERROR;
	*S.top++ = e;
	return OK;
}

double Popd(SqStackd &S){
	if(S.base == S.top) return ERROR;
	return *--S.top;
}

double GetTopd(SqStackd S){
	if(S.top == S.base) return ERROR;
	return *(S.top - 1);
}

// 判断字符是操作数还是运算符 
int In(char ch){
	switch(ch){
		case'+':
		case'-':
		case'*':
		case'/':
		case'(':
		case')':
		case'=': 
			return 1;
			break;
		default:
			return 0;
			break;
	}
}

//  比较优先级,top 栈顶运算符,outside 栈外运算符 
char Precede(char top, char outside){
	int a,b;
	switch(top){
		case'+':
			a = 0;
			break;
		case'-':
			a = 1;
			break;
		case'*':
			a = 2;
			break;
		case'/':
			a = 3;
			break;
		case'(':
			a = 4;
			break;
		case')':
			a = 5;
			break;
		case'#':
			a = 6;
			break;
		default: break;
	}
	switch(outside){
		case'+':
			b = 0;
			break;
		case'-':
			b = 1;
			break;
		case'*':
			b = 2;
			break;
		case'/':
			b = 3;
			break;
		case'(':
			b = 4;
			break;
		case')':
			b = 5;
			break;
		case'=':
			b = 6;
			break;
		default: break;
	}
	return precede[a][b]; 
}

// 运算求值函数 
double operate(double a,char theta,double b){
	switch(theta){
		case'+':
			return a + b;
			break;
		case'-':
			return a - b;
			break;
		case'*':
			return a * b;
			break;
		case'/':
			return a / b;
			break;
	}
}

// 表达式求值总函数 
int EvaluateExpression(SqStack &OPTR,SqStackd &OPND,char *str){
	InitStack(OPTR);
	InitStackd(OPND);
	Push(OPTR,'#');
	
	char ch;			// 当前字符
	int i = 0;			// 用于扫描字符串下标 
	char z[100] = {};	// 用于暂时存放数字的字符串
	int j = 0;			// 数字和小数点构成的字符串下标 
	
	while(1){
		ch = str[i];
		if(ch == '\0') break;	// 字符串未结束,循环继续
		
		if(In(ch)){	// 运算符 
			switch(Precede(GetTop(OPTR),ch))
			{	// 比较运算符栈顶元素和ch的优先级 
				case'>':
					char theta;		// 运算符 
					double a,b,c;	// 运算数a,运算数b,运算结果c 
					theta = Pop(OPTR);
					b = Popd(OPND);
					a = Popd(OPND);
					c = operate(a,theta,b);
					Pushd(OPND,c);
					break;
				case'<':
					Push(OPTR,ch);
					i++;
					ch = str[i]; 
					break;
				case'=':
					Pop(OPTR);
					i++;
					ch = str[i];
					break;
				default:
					i++;
					ch = str[i];
					break;
			}
		}
		else{
			while((ch >= '0' && ch <= '9') || ch == '.'){ // 操作数和小数点,先存进数组再转换为浮点型存入栈
				z[j] = ch;
				j++;
				i++;
				ch = str[i];
			}
			z[j] = 'a';	 // 在数组存放数字后加一字母,用于atof函数转化 
			double d = atof(z);
			memset(z,'\0',sizeof(z)); j = 0;	// 把数组置空,下标置为0,等待下一个运算数进入 
			Pushd(OPND,d);
		}
	}
	cout << fixed << setprecision(2) << GetTopd(OPND) << endl;
}

int main(){
	char ch = NULL;
	char str[MAXSIZE] = {};	// 输入的字符串算术表达式
	
	while(true){
		cin >> str; 		// 输入表达式
		ch = str[0]; 		// 如果输入为等号则结束 
		if(ch == '=')
			break;
		else{
			SqStack OPTR;
			SqStackd OPND;
			EvaluateExpression(OPTR,OPND,str);
		}
	}
	
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值