基于广义表的算术表达式的实现

                   看过数据结构书上有个算术表达式的实现,觉得实现比较麻烦,用到了队列,栈还有一个难以建立的运算符优先级比较表,在最初看那个本书的时候写了估计一天,最近又在重新温习数据结构,再看打那个表达式的时候,突然想到可以用广义表通过递归建立和运算得到运算结果,实现起来感觉思想上还是比较容易理解的,可能是算法的基础还有有点薄弱,下面的代码几乎写了6个小时,弱爆了。

                 写的时候发现,百度也可以直接对表达式给出运算结构,框计算太牛逼了····

 

.h   文件·

/* 定义节点类型,三中情况,数据、操作符、链表 */
typedef enum{OPND,OPTR,LIST} ElemTag;

typedef double Number;

typedef char Operator;

typedef struct node
{
	/* tag用来标识改节点的类型 */
	ElemTag  tag;
	
	/* 节点的数据,共用体表示 */
	union
	{
		Number data;
		Operator  optr;
		struct node * hp;
	};
	struct node * next;
}GList , * pGList;

int GetNext(char * str,char * host,int* NumOrOpt,int Count);
int CreateList(pGList  *L ,char* S);
int isNum(char c);

#include <math.h>

/* 根据传入的操作符和两个运算数返回结果 */
double Calculate(double opnd1,double opnd2,char optr)
{
	switch( optr )
	{
	case '+':	return opnd1 + opnd2;
		break;
	case '-':	return opnd1 - opnd2;
		break;
	case '*':	return opnd1 * opnd2;
		break;
	case '/':	return opnd1 / opnd2;
		break;		
	default:break;
	}
}

/*对传进来的表达式字符串通过递归操作*/
int CreateList(pGList * L,char * str)
{
	char host[20] = {0};
	int NumOrOpt = 0;
	int Count = 0 ;

	pGList  p;
	if( !(L) ) return 0;
	*L =  ( GList*) malloc(sizeof(GList));
	p = *L;

	memset(p,0,sizeof(GList) );

	/* 将表达式存入到广义链表,带括号的话又递归存入到子链表 ,每个链表的第一个是不存储数据是*/
	while( str[Count] != 0 )
	{
		Count=GetNext(str,host,&NumOrOpt,Count);
	/*	printf("%4d,%s NumOrOpt=%d\n",Count,host,NumOrOpt);*/
		
		/*遇到右括号表示结束,不在继续分配内存*/
		if( NumOrOpt < 6 )
		{
			p ->next = ( GList*) malloc(sizeof(GList));
			memset(p->next,0,sizeof(GList) );
		}
		
		/* 根据不同的NumOrOpt数值,标识当前host装入的不同类型数据
		如果是一个 左括号 (  开始一个新的子链表,如果是右括号)表示当前链表结束*/
		switch( NumOrOpt )
		{
		case 0 :	p->next->tag = OPND;
					p->next->data = atof(&host);
			break;	
		case 1:	p->next->tag = OPTR;
			p->next->optr= host[0];
			break;		
		case 2 :	p->next->tag = LIST;
					Count += CreateList(&(p->next->hp),&str[Count]);	/* 将分析了字符个数加到Count上,以便下次分析 */
			break;	
		case 3 :
			return Count;		/* 返回当前链表分析了的字符个数 */
			break;

		default: break;
		}
		p = p ->next;
		memset(host,0,20);
	}

	return 0;
}

/*对存储了运算表达式的广义链表计算,
最后得到的答案就在广义链表的头结点的数据域data*/
void CalList(GList  * lp)
{
	GList * pt = 0 ;
	GList * pa = 0 ;
	int i,flag ;
	pt= lp->next;

	/* 搜索最里层的单项表达式(没有括号的) */
	while(pt)
	{
		if( pt->tag == LIST )
		{
			CalList(pt->hp);
			pt->tag = pt->hp->tag;
			pt->data = pt->hp->data;

		}
		pt = pt->next;
	}
	
	/* 将最里层的单项表达式的结果运算出来,存放到该链
	表自身的头节点,同时清除已经被运算了的节点,头结点是没有数据的*/
	i = 2;
	while(i>0)	/* 这里的运算是在确保没有括号的情况下 先对乘除运算,同时去除被运算了的数据节点 */
	{
			pt  = lp->next ;	
			while(( pt && pt->next&& pt->next->next ))
			{
				if( !(pt->next && pt->next->next ))
				{
					printf("Error expression!! %c\n",pt->optr);
					exit(1);
				}			
				/* 第二次运算就是对加减运算了  */
				if( pt->next->tag == OPTR && (( pt->next->optr == '*' || pt->next->optr == '/') || i == 1 ))
				{
					pa = pt->next;

					pt->data = Calculate(pt->data,pa->next->data,pa->optr);

					pt->next = pt->next->next->next;
					free(pa->next);
					free(pa);
					
					continue;
				}
				pt = pt->next;
			}
		--i;	
	}
	/* 结果保存到子链表的本身处 */
	lp->tag = OPND;
	lp->data = lp->next->data;
	free(lp->next);
	lp->next = 0;
}

/*输出广义链表*/
void ShowList(GList  * lp)
{
	GList * pt = 0 ;

	pt  = lp->next ;
	while(pt)
	{
		if( pt->tag == LIST )
		{
			ShowList(pt->hp);
		}
		if( pt->tag == OPND )
			printf("%lf ",pt->data);
		if( pt->tag == OPTR )
			printf("%c ",pt->optr);
		pt = pt->next;
	}
	printf("\n");
}

/*从第Count个元素开始分析,如果后面紧接着一个数
据就通过host返回,NumOrOpt为1-6表示当前host存储了不同的类型的数据
0:存储的是数据,1到4表示+、-、*、/四种操作,5 6分别表示 ( )*/
int GetNext(char * str,char * host,int* NumOrOpt,int Count)
{
	int   flag ,n ,epos;

	if(!(str && host && NumOrOpt))
		return 0;

	n =  Count ;

	flag = IsNum(str[n]);
	
	while( str[n] && flag == IsNum(str[n]) )
	{
		if(   ')' == str[n++]  ||   '(' == str[n]  )
			break;
	}
	
	/*把从Count处开始分析的字符串保存到host,要么是一个数值的字符串,有么是一个操作符*/
	strncpy(host,&str[Count],n-Count);
	
	switch( host[0] )
	{
		case '+' :	*NumOrOpt = 1;
			break;	
		case '-' :	*NumOrOpt = 1;
			break;	
		case '*' :	*NumOrOpt = 1;
			break;		
		case '/' :	*NumOrOpt = 1;
			break;
		case '(' :	*NumOrOpt = 2;
			break;			
		case ')' :	*NumOrOpt = 3;
			break;			
		default: *NumOrOpt = 0;
	}
		
	return n;
}

/*判断字符c是否为字符*/
int IsNum(char c)
{
	if(( c >= '0' && c <= '9') || '.' == c )
		return 1;
	return 0;
}


验证结果的

#include "biaodashi.h"

main()
{

	char str[100]="((5)*19*6*(6*(4*(5*9-4/(9-2))))+2*(1.5*(18.4+1.6*(2-1)))/10-52*(5+2*0.25*9))";
		
	GList * L;

	printf("Please Input a legal expression!\n");
	
//	gets(str);

	printf("%s \n",str);

	CreateList(& L, str);
		
	CalList(L);
	printf("The Answer is  %lf\n",L->data);

}
 
运算结果:
可以直接在百度搜索框里面输入(5)*19*6*(6*(4*(5*9-4/(9-2))))+2*(1.5*(18.4+1.6*(2-1)))/10-52*(5+2*0.25*9)) 得到的同样的运算结果,小数点后面若干位就不管了。

 

基于广义表的算术表达式的实现_第1张图片

你可能感兴趣的:(基于广义表的算术表达式的实现)