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