C语言课设:中缀表达式转后缀表达式并求值(续)

版权声明:本文由 高小调 创作,转载请带链接,侵权必究! https://blog.csdn.net/gaoben668/article/details/53239421

前天看到有人给我很久之前写的一篇博客《C语言::将中缀表达式转换为后缀表达式并计算结果》指出了一个BUG.

今天闲的没事,就把BUG修复一下,一看那代码写的,不忍直视,那个BUG更是让我啼笑皆非...

这就是传说中的成长吧!看过去的自己总觉得像个傻逼

-----------------------------------------------------------------------

本次程序升级说明:

1.修复了将除法计算为减法的BUG.

2.修复了一些内存泄漏的情况

3.对代码进行了分文件实现

4.将使用的库函数声明在了头文件里,降低编译依存性.(最近才学的,对这块还有些迷糊,不知道这样做对不对)

集成开发环境:vs 2010

-------------------------------------------------------------------------


代码如下:

Stack.h //栈的声明

#ifndef __STACK_H__
#define __STACK_H__
#define ElemType int
/////栈的结构////////
typedef struct Stack{
	ElemType * base;
	ElemType * top;
	int stacksize;
}SqStack;
////用到库函数的声明////////
//单独声明,为了降低编译依存性
#define NULL 0;
void exit(int);
void *malloc(unsigned);
void *realloc(void *,unsigned);
void free(void *);
/////////////

//初始化一个栈
int CreateStack(SqStack * S);
//获得栈顶元素 
ElemType GetTop(SqStack * S);
//压栈 
int Push(SqStack * S,ElemType e);
//弹出 
int Pop(SqStack * S,ElemType * e);
//销毁栈
void DestoryStack(SqStack * S);
#endif


Stack.c  //栈的实现

#include"Stack.h"
//初始化一个栈 
int CreateStack(SqStack * S){
	S->base = (ElemType *)malloc(sizeof(SqStack)*10);
	if(!S->base) exit(-1);
	S->top = S->base;
	S->stacksize = 10;
	return 1;
}
//获得栈顶元素 
ElemType GetTop(SqStack * S){
	if(S->top == S->base)
		return 0;
	return *(S->top-1);
}
//压栈 
int Push(SqStack * S,ElemType e){
	if((S->top-S->base)>=S->stacksize){
		S->base = (ElemType *)realloc(S->base,(S->stacksize+5)*sizeof(SqStack));
		if(!S->base)
			exit(-1);
		S->top = S->base + S->stacksize;
		S->stacksize +=5;
	}
	*S->top=e;
	S->top++;
	return 1;
}
//弹出 
int Pop(SqStack * S,ElemType * e){
	if(S->top==S->base)
		return 0;
	*e = *(--S->top);
	return 1;
}
//销毁栈
void DestoryStack(SqStack * S){
	free(S->base);
	S->base = NULL;
	S->top = NULL;
	S->stacksize = 0;

}


Expression.h   //与表达式相关函数声明

#ifndef _EXPRESSION_H__
#define _EXPRESSION_H__
#include"Stack.h"
///////////用到的库函数///////////
//声明在这里,降低编译依存性
#define NULL 0
void *malloc(size_t);
char *strcpy(char*,char*);
char *gets(char*);

////////////自己的函数////////
//基本的元运算 
ElemType Theta(int l,char m,int r);
int Is_Pop(char x,char y);
//创建中缀表达式 
void CreateExpression(char * str);
//判断是否为运算符 
int In_Op(char a);
/*
函数功能:将中缀表达式转换为后缀表达式 
	参数:中缀表达式
返 回 值:后缀表达式 
*/
char * TransmitExpression(char * a);
//根据后缀表达式计算结果 
ElemType EvaluateExpression(char *a);
#endif


Expression.c //表达式函数相关实现

#include"Expression.h"
//基本的元运算 
ElemType Theta(int l,char m,int r){
	switch(m){
		case'+': return l+r;
		case'-': return 1-r;
		case'*': return l*r;
		case'/': return l/r;
	}	
}
//判断栈内与栈外运算符的优先级,然后再次判断是否将栈内元素弹出 
/*
 	  栈外 
 栈    + - * / ( )
 内	+  1 1 0 0 0 1
 	-  1 1 0 0 0 1
 	*  1 1 0 0 0 1
 	/  1 1 1 1 0 1
 	(  0 0 0 0 0 0
 	)  1 1 1 1 1 1
*/ 
int Is_Pop(char x,char y){
	if(x=='(')
		return 0;
	if(y=='('&&x!=')')
		return 0;
	if(y=='*'||y=='/'){
		if(x=='+'||x=='-')
			return 0;
	}
	return 1;
}
//创建中缀表达式 
void CreateExpression(char * str){
	gets(str);
}
//判断是否为运算符 
int In_Op(char a){
	switch(a){
		case '+' : return 1;
		case '-' : return 1;
		case '*' : return 1;
		case '/' : return 1;
		case '(' : return 1;
		case ')' : return 1;
		case '#' : return 1;
		default:return 0;
	}
}
/*
函数功能:将中缀表达式转换为后缀表达式 
	参数:中缀表达式
返 回 值:后缀表达式 
*/
char * TransmitExpression(char * a){
	int i,j=0;
	char b[20]={0};
	char * result = NULL;
	SqStack OPTR;
	ElemType e;
	CreateStack(&OPTR);
	Push(&OPTR,'#'); 
	for(i=0;a[i];i++){
		if(!In_Op(a[i])){
			b[j++]=a[i];//如果不是运算符则直接入b 
		}else{
			if(GetTop(&OPTR)=='#'){
				Push(&OPTR,a[i]);	//如果栈顶元素为空,直接入栈。 
				continue; 
			}
			if(Is_Pop(GetTop(&OPTR),a[i])){ //如果栈内运算符优先级高于表达式运算符优先级 
				if(a[i]==')'){	//如果遇到右括号 
					while(GetTop(&OPTR)!='('){
						Pop(&OPTR,&e);	//将左括号以上的运算符弹出并存入b 
						b[j++]=(char)e;
					}
					Pop(&OPTR,&e); //将左括号弹出 
				}else{ 			//如果不是括号情形 
					while(GetTop(&OPTR)!='#'){//将栈内所有运算符弹出 
						Pop(&OPTR,&e);
						b[j++]=(char)e;
					}
					Push(&OPTR,a[i]);//将新运算符入栈 
				}
			}else{
				Push(&OPTR,a[i]); //如果栈内优先级低于新运算符,
								//则新运算符直接入栈 
			}
		}
	}
	//中缀表达式扫描完成后,弹出所有剩下的运算符 
	while(GetTop(&OPTR)!='#'){
		Pop(&OPTR,&e);
		b[j++]=(char)e;
	}
	//新分配一个内存,用于返回 
	result = (char *)malloc(sizeof(char)*20);
	strcpy(result,b);//将b中的元素结果复制到新分配内存中
	//销毁栈
	DestoryStack(&OPTR);
	return result;
}

//根据后缀表达式计算结果 
ElemType EvaluateExpression(char *a){
	int i;
	ElemType l = 0,r = 0,e = 0,ret = 0;
	
	SqStack OPND;
	CreateStack(&OPND);
	for(i=0;a[i];i++){
		if(!In_Op(a[i])){
			Push(&OPND,(ElemType)(a[i]-48));
		}else{
			Pop(&OPND,&r);
			Pop(&OPND,&l);
			Push(&OPND,Theta(l,a[i],r));
		}
	}
	ret = GetTop(&OPND);
	DestoryStack(&OPND);
	return ret;
}


Test.c //测试文件

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"Stack.h"
#include"Expression.h"
//测试函数
void Test(){
	char str[30];
	char s_str[30];
	char *p = NULL;
	CreateExpression(str);
	p = TransmitExpression(str);
	strcpy(s_str,p);
	printf("后缀表达式为:%s\n",s_str);
	printf("最终结果为:%d\n",EvaluateExpression(s_str));
	free(p);
}
int main(){
	Test();
	return 0;

总结:这次修改,只是简单的调整了一下,其中还有很多地方设计不合理,比如表达式转换后返回了一个堆地址,这样的接口直接给用户使用是容易出问题的,因为还得依靠用户自己去手动释放资源.

虽然知道了这个东西不合理,但我也懒得再去搞了,毕竟很久之前的代码了,这本来是帮同学做数据结构课设的,现在...也用不上了!

最后附上VS工程文件:链接:http://pan.baidu.com/s/1slD4CrF 密码:nyg3

用VS系列编译器打开!用VS系列编译器打开!用VS系列编译器打开!告诉这些编程小白同学)

恩...就这样..

猜你喜欢

转载自blog.csdn.net/gaoben668/article/details/53239421