当前位置:文档之家› 数据结构之表达式求值课程设计报告

数据结构之表达式求值课程设计报告

表达式求值一目的通过课程设计,巩固和加深对线性表、栈、队列、字符串、树、图、查找、排序等理论知识的理解;掌握现实复杂问题的分析建模和解决方法(包括问题描述、系统分析、设计建模、代码实现、结果分析等);提高利用计算机分析解决综合性实际问题的基本能力。

二需求分析此次课程设计的目标是能够设计一个程序,演示算术表达式求值的过程。

①输入的形式和输入值的范围:以字符串的形式输入表达式,以换行符结束;②输出的形式:在计算过程中遇到的问题或最终的答案将回显到屏幕上,同时所计算的表达式和最终的显示也将保存至文件中;③程序所能达到的功能:能够处理以字符序列的形式输入的不含变量的实数表达式,正确处理负数与小数,判断表达式是否语法正确(包含分母不能为零的情况),正确实现对算术四则混合运算表达式的求值,能够将计算中遇到的问题和结果以文件的形式予以存储;④初步的测试计划:当输入正确表达式时,以换行符结束,能得到最终的正确结果;当输入含有非正常符号的错误表达式时,以换行符结束,能得到最终的提示语句;当遇到分数为0的轻快是,能得到提示语句。

三概要设计1、本程序中用到的数据类型该设计主要运用的是栈的知识。

为实现表达式求值的功能,需分别定义数字栈与符号栈。

其结构体定义如下:typedef struct tagstack1{ /*数据栈*/double* base; /*栈底指针*/int top; /*栈顶*/int len; /*栈的容量*/}STACK1;typedef struct tagstack2{ /*符号栈*/char* base; /*栈底指针*/int top; /*栈顶*/int len; /*栈的容量*/}STACK2;为了便于标记程序运行的正确与否,为了便于文件指针的应用,该程序定义了两个全局变量,如下:int wr=0; /*wr用于标记是否出错*/FILE* fp; /*指向文件的指针*/2、程序的简单流程与主要函数该设计主要在主函数中通过while循环来多次调用对一个表达式的处理函数ss();函数ss()调用了多个函数来实现对一个表达式的处理功能,其中,主要的函数如下:char DealNbr(STACK1* S,char a,char* * pstr,int *i)/* 若字符a是数字字符,则从字符串*pstr中继续读取字符,将数字整体的读出后,进行处理,并将最后的数字如数字栈S */char Compare(char a,char b)/* 比较两字符的优先级,若a较高则返回字符>,相同则返回=,较低则返回< */double calculate(double a,double b,char c)/* 计算数字a与数字b经运算符c计算后的结果,并返回 */int change(char c) /* 获得符号c的优先级 */void Init1(STACK1 * S) /* 初始化数据栈S */void Full1(STACK1 *S) /* 判断栈是否已满若满则追加空间*/int Empty1(STACK1 S) /*判断栈是否为空若为空则返回真值*/ void Push1(STACK1 *S,double e) /*数据e入栈*/void Pop1(STACK1 *S,double* e) /*数据出栈用e返回*/double GetTop1(STACK1 S) /*返回栈顶数据*/符号栈的有关符号与数字栈相似,不重复记录。

3、函数之间的调用关系main( ) ->ss( );ss( ) ->DealNbr( ); Compare( ); calculate( ); change( );Init1( ); Push1( ); Empty1( ); Pop1( ); GetTop1( );等一系列栈的函数四详细设计1、Init1(STACK1 * S):void Init1(STACK1 * S){/*初始化数据栈*/(*S).len=StackSize;(*S).base=(double *)malloc(sizeof(double)*StackSize);if(!(*S).base){wr=1;printf("\n\nSpace!!");fprintf(fp,"Space!!\n\n");return;}(*S).top=-1;}令栈初始容量为StackSize,并为栈底指针分配相应空间。

若未分配成功,则标记出错,否则,令栈顶为-1,此时,栈内没有元素;2、Push1(STACK1 *S,double e):void Push1(STACK1 *S,double e){/*数据e入栈*/Full1(S);(*S).top++;*((*S).base+(*S).top)=e;}先判断栈是否已满,若满则增加空间。

令栈顶自加,并将元素入栈。

3、Pop1(STACK1 *S,double* e):void Pop1(STACK1 *S,double* e){/*数据出栈用e返回*/if((*S).top==-1){wr=1;printf("\n\nArithmetic expression wrong!!");fprintf(fp,"Arithmetic expression wrong!!\n\n");return;}*e=*((*S).base+(*S).top);(*S).top--;}若栈为空,则提示出错,否则,用e返回栈顶元素,并令top自减。

数字栈的相关函数与符号栈相似,在此,符号栈相关函数的定义将不再重复。

4、DealNbr(STACK1* S,char a,char* * pstr,int *i):char DealNbr(STACK1* S,char a,char* * pstr,int *i){/*数字字符则进行处理并入栈*/double d1=0,d2=1;while(a>='0'&&a<='9'){a-='0';d1=d1*10+a;a=(*pstr)[(*i)++];}if(a=='.'){a=(*pstr)[(*i)++];while(a>='0'&&a<='9') {d2/=10;a-='0';d1+=d2*a;a=(*pstr)[(*i)++];}/*while*/}/*if*/Push1(S,d1);return a;}若字符a是数字字符,则继续从字符串中读取字符,直到不再是数字字符,处理后保存在d1中;若紧接着是小数点字符,则说明此数为实数;继续读取字符,若是数字字符则继续处理,直到不再是数字字符。

最终将字符串中的一串数字字符转化为实数,并将此数入数字栈。

5、change(char c):int change(char c){/*获得符号c的优先级*/if(c=='\x0') return 1;if(c=='+'||c=='-') return 2;if(c=='*'||c=='/') return 3;if(c=='('||c==')') return 4;return 0;}因字符串的最后一个字符为’\x0’,所以令其的优先级最低;令’+’和’-’为2,比乘除和括号要低;令’*’和’/’的优先级为3,比括号低;令括号的优先级最高。

6、Compare(char a,char b):char Compare(char a,char b){/*比较两字符的优先级*/if(a=='('&&b==')') return '=';if(a==')'&&b=='('){wr=1;printf("\n\nArithmetic expression wrong!!");fprintf(fp,"Arithmetic expression wrong!!\n\n");return 0;}if(a=='('||b=='(') return '<';if(a==')'||b==')') return '>';if(change(a)>=change(b)) return '>';else return '<';}左右括号的级别相同;若右括号紧接左括号,则表达式出错;若左括号紧接左括号,则后面的括号优先级较高;若右括号紧接右括号,则前面的括号优先级较高;其他情况下,则是change值较大的或位置比较靠前的字符优先级高;7、calculate(double a,double b,char c):double calculate(double a,double b,char c){/*计算数字a与数字b经运算符c计算后的结果,并返回*/switch(c){case '+': return a+b;case '-': return a-b;case '*': return a*b;case '/': if(!b){wr=1;printf("\n\nDivisor is zero!!");fprintf(fp,"Divisor is zero!!\n\n");return FALSE;} return a/b;default:wr=1;printf("\n\nArithmetic expression wrong!!");fprintf(fp,"Arithmetic expression wrong!!\n\n");return FALSE;}/*switch*/}/*calculate*/运用switch语句,不同的运算符则进行不同的运算;进行除法时,若分母为0,则将标志标记成错误,并退出这个函数;若不是运算符,则同样标志错误,退出函数。

8、ss(double* a,char* * pstr):int ss(double* a,char* * pstr){/*对表达式的处理*/STACK1 OPND;STACK2 OPTR;double nbr1=0,nbr2=0;char c=0,d=0,e=0;int i=0;Init1(&OPND);Init2(&OPTR); /*初始化*/if(wr) return FALSE; /*空间分配不成功*/Push1(&OPND,0); /*默认数据栈中的初始化元素为0*/Push2(&OPTR,'0'); /*将符号零入符号栈作为标记*/c=(*pstr)[i++]; /*取得输入字符串的第一个字符*/if(c=='(')Pop1(&OPND,&nbr1); /*若第一个字符为左括号则将0出栈*/ if(c>='0'&&c<='9'){Pop1(&OPND,&nbr1);c=DealNbr(&OPND,c,pstr,&i);}/*若为数字字符则0出栈并将数字处理后入数字栈*/while(c!='\0'||GetTop2(OPTR)!='0'){/*循环条件为字符均已处理或符号栈中的字符均已计算*/if(c>='0'&&c<='9'){if(GetTop2(OPTR)=='(') Pop1(&OPND,&nbr1);/*若前一个字符为左括号则将0出栈*/c=DealNbr(&OPND,c,pstr,&i); /*处理数字并入数字栈*/if(e=='='){ /*若前一个符号为右括号则出错*/wr=1;printf("\n\nArithmetic expression wrong!!");fprintf(fp,"Arithmetic expression wrong!!\n\n");}if(wr) return FALSE; /*空间分配不成功*/}/*if*/if(!change(c)){ /*未知符号存在*/wr=1;printf("\n\nWrong character exist!!");fprintf(fp,"Wrong character exist!!\n\n");return FALSE;}if(c=='('){ /*若收到左括号则将0入数字栈便于处理负数*/ Push1(&OPND,0);if(wr) return FALSE; /*空间分配不成功*/}e=Compare(GetTop2(OPTR),c); /*比较栈顶符号与当前符号的优先级*/ switch(e){case '<':Push2(&OPTR,c); /*若当前符号优先级高则入栈*/ if(wr) return FALSE; /*空间分配不成功*/c=(*pstr)[i++]; /*读取下一个字符*/break;case '=':Pop2(&OPTR,&d); /*若两符号优先级相同则为左右括号出栈*/ c=(*pstr)[i++];break;case '>':Pop2(&OPTR,&d);/*若栈顶符号的优先级高则出栈并计算将结果入数字栈*/Pop1(&OPND,&nbr1);Pop1(&OPND,&nbr2);if(wr) return FALSE; /*栈空*/nbr1=calculate(nbr2,nbr1,d);if(wr) return FALSE; /*除数为零*/Push1(&OPND,nbr1);if(wr) return FALSE; /*空间分配不成功*/break;}/*switch*//*else*/}/*while*/Pop1(&OPND,a); /*将数字栈栈顶数据出栈放入a*/if(Empty1(OPND)&&GetTop2(OPTR)=='0') return TRUE;/*若两栈中都没有多余字符则说明成功计算了表达式*/printf("\n\nArithmetic expression wrong!!"); /*否则提示出错*/fprintf(fp,"Arithmetic expression wrong!!\n\n");return FALSE;}此函数为该课程设计的核心部分。

相关主题