栈的应用-算术表达式求值

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INIT_SIZE 20
#define INCREMENT 10
//创建操作数栈 
typedef struct OprdSatck
{
	double *top;
	double *base;
	int stackSize;
}OPRD;
//创建运算符栈
typedef struct OptrStack
{
	char *top;
	char *base;
	int stackSize;
}OPTR;
//创建操作数栈
void InitOprdStack(OPRD *oprd)
{
	oprd->base=(double*)malloc(INIT_SIZE*sizeof(double));
	if(oprd->base==NULL)
	exit(0);
	oprd->top=oprd->base;
	oprd->stackSize=INIT_SIZE;
}
//创建运算符栈
void InitOptrStack(OPTR *optr)
{
	optr->base=(char*)malloc(INIT_SIZE*sizeof(char));
	if(optr->base==NULL)
	exit(0);
	optr->top=optr->base;
	optr->stackSize=INIT_SIZE;
}
//输入表达式 
void inputStr(char str[])
{
	printf("请输入字符串表达式(输入#表示结束):\n");
	gets(str);	
}
//判断字符的类型
int getType(char ch)
{	
		if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#')
		return 1;
		else 
		return 0; 
}
char optr[7]={'+','-','*','/','(',')','#'};
char op[7][7]={
	{'>','>','<','<','<','>','>'},
	{'>','>','<','<','<','>','>'},
	{'>','>','>','>','<','>','>'},
	{'>','>','>','>','<','>','>'},
	{'<','<','<','<','<','=',' '},
	{'>','>','>','>',' ','>','>'},
	{'<','<','<','<','<',' ','='}
};
char compare(char op1,char op2)
{//op1为栈顶运算符,op2是扫描读到的运算符 
	int i=0,j=0;
	while(optr[i]!=op1)
	i++;
	while(optr[j]!=op2)
	j++;
	return op[i][j]; 
}
//操作数入栈
void pushOprd(OPRD *oprd,double d)
{
	if(oprd->top-oprd->base>=oprd->stackSize)
	{
		oprd->base=(double*)realloc(oprd->base,(oprd->stackSize+INCREMENT)*sizeof(double));
		if(!oprd->base)
		exit(0);
		oprd->top=oprd->base+oprd->stackSize;
		oprd->stackSize=oprd->stackSize+INCREMENT;
	}
	*(oprd->top)=d;
	oprd->top++;
}
//运算符入栈
void pushOptr(OPTR *optr,char ch)
{
	//栈满 
	if(optr->top-optr->base>=optr->stackSize)
	{
		optr->base=(char*)realloc(optr->base,(optr->stackSize+INCREMENT)*sizeof(char));
		if(optr->base==NULL)
		exit(0);
		optr->top=optr->base+optr->stackSize;
		optr->stackSize=optr->stackSize+INCREMENT;	
	} 
	*(optr->top)=ch;
	optr->top++; //栈顶上移 
} 
//操作数出栈 
void popOprd(OPRD *oprd,double *d)
{
	if(oprd->top==oprd->base)
	{
		printf("空栈,操作数出栈错误!\n");
		exit(0);
	} 
	*d=*(--oprd->top);
}
//运算符出栈
void popOptr(OPTR *optr,char *ch)
{
	if(optr->top==optr->base)
	{
		printf("空栈,运算符出栈错误!\n");
		exit(0);
	}
	*ch=*(--optr->top);
}
//获取操作数栈顶元素
double getOprdTop(OPRD *oprd)
{
	if(oprd->top==oprd->base)
	{
		printf("空栈,获取操作数栈顶元素失败!\n");
		exit(0);
	}
	return *(oprd->top-1);//!!!
}
//获取运算符栈顶元素
char getOptrTop(OPTR *optr)
{
	if(optr->top==optr->base)
	{
		printf("空栈,获取运算符栈顶元素失败!\n");
		exit(0);
	}
	return *(optr->top-1);
}
//计算 
double operate(double a,char op,double b)
{
	switch(op)
	{
		case '+':
			return a+b;
			break;
		case '-':
			return a-b;
			break;
		case '*':
			return a*b;
		case '/':
			return a*1.0/b;
			break;
		default:
			printf("输入错误!\n");
	}
}
//处理表达式
void fight(char ex[],OPRD *oprd,OPTR *optr)
{
	double data,a,b;//a,b是表示弹出栈的操作数,data存储弹出来计算的结果 
	char op;//存储从栈顶取出的运算符 
	char charData[20];//存储字符型的数字
	int i=0;//ops的索引 
	char *p=ex; //遍历表达式 
	printf("运算过程如下:\n");
	while(*p!='#'||getOptrTop(optr)!='#')
	{
		if(getType(*p)==0)//不是运算符!
		{
			charData[i]=*p;//先存储到ops数组
			p++;
			++i; 
			if(getType(*p)==1)//下一个不是数字!
			{
				charData[i]='\0';
				data=atof(charData);//atof把字符串变成浮点数
				pushOprd(oprd,data);//把data入栈 
				i=0;//归零 
			}
		 }
		 else
		 {
		 	switch(compare(getOptrTop(optr),*p))
		 	{
		 		case '<'://比栈顶运算符优先级高,新运算符压栈 
		 			pushOptr(optr,*p);
		 			p++; 
					 break;
				case '='://脱括号 
				 popOptr(optr,&op);
				 p++;
				 break;
				 case '>'://比栈顶运算符优先级低,运算!
				 popOptr(optr,&op);
				 popOprd(oprd,&a);
				 popOprd(oprd,&b);
				 pushOprd(oprd,operate(b,op,a));
				 printf("%.2lf%c%.2lf=%.2lf\n",b,op,a,operate(b,op,a));
				 break;
			 }
		  } 
	}
} 
main()
{
	//1,创建操作数栈和运算符栈 
	OPRD oprd;
	OPTR optr;
	InitOprdStack(&oprd); 
	InitOptrStack(&optr);
	pushOptr(&optr,'#');//把#先压栈 
	//2,输入表达式
	char ex[80];
	inputStr(ex);
	fight(ex,&oprd,&optr);
	printf("\nresult=%.2lf",getOprdTop(&oprd)) ;
 }
 

我是初学数据结构的小菜鸡,水平有限,查找了很多资料才得以理解,写第一篇博客,以此缅怀这段痛苦并收获的时光。
易错点:
1,栈顶指针,指向的是栈顶元素的上一个位置!
2,pop(OPRD *oprd,double *d);用指针的方法来接收出栈的值!如果用double d做参数,d的值不会改变!
难点:
1,比较运算符的优先级(解决:使用二维数组)
2,怎么让操作数和运算符入栈出栈:
遍历表达式字符串,只需要判断是否为运算符即可!!!
(1)当前扫描到的运算符优先级高于栈顶运算符,直接把新的运算符入栈
(2)当前扫描到的运算符优先级等于栈顶运算符,去括号
(3)当前扫描到的运算符优先级等于栈顶运算符,运算符栈顶元素出栈,操作数栈出栈两个操作数,进行运算,把运算结果再入操作数栈。
3,怎么提取到表达式字符串中的操作数:
如果该字符是数字,先存储到一个字符数组里并判断下一个字符是否为数字:
如果下一个字符是数字,继续遍历表达式字符串。
如果不是,使用atof(字符数组)函数,把字符串的数字转换为浮点数!
此方法解决了小数的问题!
在这里插入图片描述
运行结果如上图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值