数据结构_表达式计算,可解 -99.12*(3.2+(-0.65))/2+2^3#(全)

可计算表达式中带有:负数、小数、不止是个位数

-99.12*(3.2+(-0.65))/2+2^3#
(-3.125+(-0.125))*2/(-2)#
2/0#

作者说明

学习中,我发现网上没有找到计算表达式 较系统的解答。要么只能计算个位数,要么不能有小数点等等

难点说明

  1. 栈的基本操作
  2. 数字的提取 负数的处理 小数的处理
  3. 后缀表达式的理解

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define INITSIZE 100
#define STACK_INCREASE 10
typedef struct {//存字符
	char *base;
	char *top;
	int stacksize;
}Stack_1;    //符号位 
typedef struct {//存数字
	float *base;//double当然也可以
	float *top;
	int stacksize;
}Stack_2;       //数字位 
Stack_1 S;     //声明在这里,为函数传值更有效
Stack_2 S2;

int InitStack(Stack_1 &S,Stack_2 &S2){//一起初始化
	S.base=(char *)malloc(INITSIZE*sizeof(char));
	S2.base=(float *)malloc(INITSIZE*sizeof(float));
	if(!S.base||!S2.base){
		printf("初始化失败!");
		exit(0); 
	}
	S.top=S.base;
	S.stacksize=INITSIZE;
	S2.top=S2.base;
	S2.stacksize=INITSIZE;
}
int GetTop_1(Stack_1 S,char &e){//取栈顶运算符号
	if(S.base==S.top){
		printf("栈空!");	
		return 0;
	}	
	e=*(S.top-1);
	return 1;
}
int GetTop_2(Stack_2 S2, float &e){//取栈顶数字
	if(S2.base==S2.top){
		printf("栈空!");	
		return 0;
	}	
	e=*(S2.top-1);
	return 1;
}
int Push_1(Stack_1 &S,char e){//入栈
	if(S.top-S.base>=S.stacksize){
		S.base=(char*)realloc(S.base,(S.stacksize+STACK_INCREASE)*sizeof(char));
		if(!S.base){
			printf("重新分配空间失败!");
			exit(0); 
		}
		S.top=S.base+S.stacksize;
		S.stacksize+=STACK_INCREASE;
	}
	*S.top++=e;
	return 1;
}
int Push_2(Stack_2 &S2,float e){//入栈
	if(S2.top-S2.base>=S2.stacksize){
		S2.base=(float*)realloc(S2.base,(S2.stacksize+STACK_INCREASE)*sizeof(float));
		if(!S2.base){
			printf("重新分配空间失败!");
			exit(0); 
		}
		S2.top=S2.base+S2.stacksize;
		S2.stacksize+=STACK_INCREASE;
	}
	*S2.top++=e;
	return 1;
}
int Pop_1(Stack_1 &S,char &e){//出栈
	if(S.base!=S.top){
		e=*--S.top;
	}
	else {
		printf("栈空!");
	}
} 
int Pop_2(Stack_2 &S2,float &e){
	if(S2.base-S2.top!=0){
		e=*--S2.top;
	}
	else {
		printf("栈空565555555!");//个人调试时标记的东东
	}
}
int isStack_1(char ch){//确认是云算符
	if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='^'){
		return 1;
	}
	return 0;
}
int isNumber(char ch){//确认是数字  例:‘2’
	if(ch>='0'&&ch<='9'){
		return 1;
	}
	return 0;
}
int priority(char ch){             //priority和compare函数用来判断权大小
	if(ch=='+'||ch=='-')
		return 1;
	else if(ch=='*'||ch=='/')
		return 2;
	else if(ch=='#')
		return 0;
	else if(ch=='(')
		return 3;
	else if(ch==')')
		return -1;
}
int compare(char ch1,char ch2){//有点不规范,望理解
	if(ch1==')'&&ch2=='('){
		return -2;//"()"
	}
	if(ch1!=')'&&ch2=='('){
		return 2;//"*)"
	}
	if(ch1=='('&&ch2=='('){//权大 
		return 2; 
	}
	if(ch1=='^'){
		return 4;
	} 
	int a=priority(ch1);	    //调用在次
	int b=priority(ch2);		
	if(a>b) return 1;//(*
	else if(a<b) return -1;
	else return 0;
}
void countAB(Stack_2 &S2,char e){//算栈顶的两个数值 
	float a,b;
	Pop_2(S2,a);
	Pop_2(S2,b);
	switch(e){
		case '^':{
			a=powf(b,a);
			break;
		}
		case '+':{
			a=b+a;
			break;
		}
		case '-':{
			a=b-a;
			break;
		}
		case '*':{
			a=b*a;
			break;
		}
		case '/':{
			if(a==0){
				printf("分母不能为 0!\n");
				exit(0);
			}
			a=b/a;
			
			break;
		}
	}
	Push_2(S2,a);
}
 void countSum(char ch[]){

	InitStack(S,S2);
	Push_1(S,'#');
	int i=0;
	char ePass;
	while(ch[i]!='#'){
		if(i!=0){
			ePass=ch[i-1];
		}
		else{
			ePass='#';
		}
		if(ch[i]=='-'&&(ePass=='('||ePass=='#')){//特殊情况,解决负数,例:(-2)
			i++;
			float x=ch[i]-'0';
			int j=i+1;
			while(isNumber(ch[j])){
				x=x*10+ch[j]-'0';
				j++;
			}
			if(ch[j]=='.'){
				j++;
				float count=1.0;
				while(isNumber(ch[j])){
					x=x+(ch[j]-'0')*powf(0.1,count);
					count++;
					j++;
				}
			}
			x*=-1.0;
			i=j;
			Push_2(S2,x);
		
		}
		else if(isNumber(ch[i])){//是数字
			float x=ch[i]-'0';
			int j=i+1;
			while(isNumber(ch[j])){
				x=x*10+ch[j]-'0';
				j++;
			}
			if(ch[j]=='.'){
				j++;
				float count=1.0;
				while(isNumber(ch[j])){
					x=x+(ch[j]-'0')*powf(0.1,count);
					count++;
					j++;
				}
			}
			Push_2(S2,x);
			i=j;
		}
		else if(isStack_1(ch[i])){//是运算符
			char e;
			GetTop_1(S,e);
			int y=compare(ch[i],e);//**与上一个运算符比较权**
			switch(y){
				case -2:{//()
					Pop_1(S,e);
					break;
				}
				case 2:{//*(
					Push_1(S,ch[i]);
					break;
				}
				case 1:{//*+
					Push_1(S,ch[i]);
					break;
				}
				case 4:{//*+
					Push_1(S,ch[i]);
					break;
				}
				case -1:{//)+
				/**
				1.除去+
				2.+来stack_2
				3.还必须是  ) 
				*/
					Pop_1(S,e);
					countAB(S2,e);
					i--;
					break;
				}
				case 0:{
					Pop_1(S,e);
					countAB(S2,e);
					i--;
					break;
				}
			}
			i++;
		}
	}
	char e0;
	Pop_1(S,e0);
	//printf("%c\n",e0);
	while(e0!='#'){
		countAB(S2,e0);
		Pop_1(S,e0);
	}
	float sum=0;
	GetTop_2(S2,sum);
	printf("结果:%.3f\n",sum);//为了美观,保留了3位,但是对于小数多的就有缺精度的可能
}
int main(){
	char ch[50];
	while(scanf("%s",ch)){//不断输入
		countSum(ch);
	}
	return 0;
}

可运行结果

在这里插入图片描述

解释:

  1. 为什么要用后缀表达式:后缀表达式
  2. 这里的两个栈,一个存运算符,一个存数字
    这里的计算后缀表达式是边算边求的,因为这里有可以计算超过个位的数,不好给出全部后缀表达式,但是计算是利用后缀表达式的结构的。例如:33+92#的后缀表达式是:3392+
    但是33与9 连在一起了,不好分开,你可以加一个分隔符:33|9|2*2
    但这里没有给出了,避免麻烦,就直接计算了。
  3. 作业要求是将整个代码分成如下工程分块,因为操作不难,表示母鸡可以 Q 846891884,所以这里就一个整个代码块了。在这里插入图片描述
  4. 这里符号权的大小比较写的比较生涩,个人话,不太好。 运算权是可以规范化的,因为没懂,所以没有用二维数字表示,(留意)
  5. 测试:(-3.125+(-0.125))*2/(-2)#
    后面的#是可以设计删除的,也很简单
  6. 其实最难弄的就是 void countSum(char ch[]);函数了。

嘿嘿、哈哈:

有很多注释的不清楚。同时:如果这能与大整数联合起来就好了。
下次说大整数,因为我做了一点。
第一次这样的文稿,有点不太会,望理解、指错。
加油!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值