1、表达式求值表达式求值数据结构课程设计报告表达式求值专业 计算机科学与技术学生姓名班级学号指导教师完成日期表达式求值目录1 概述 (1) 课程设计目的 (1) 课程设计内容 (1)2 系统需求分析 (1) 系统目标 (1) 主体功能 (1) 开发环境 (1)3 系统概要设计 (2) 系统的功能模块划分 (2) 系统流程图 (2)4系统详细设计 (3)5 测试 (3) 测试方案 (5) 测试结果 (5)6 小结 (7)参考文献 (9)附录1 源程序清单 (10)数据结构课程设计报告(2014)表达式求值1 概述 课程设计目的1.要求学生达到熟练掌握C语言的基本知识和技能。2.了解并掌握数据结构的设
2、计方法,具备初步的独立分析和设计能力。3.提高程序设计和调试能力。学生通过上机实习,验证自己设计的算法的正确性。学会有效利用基本调试方法,迅速找出程序代码中的错误并且修改。4.培养算法分析能力。分析所设计算法的时间复杂度和空间复杂度,进一步提高程序设计水平。5.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能。 课程设计内容设计一个表达式求值的程序。该程序必须可以接受包含(,),+,-,*,/,%,和(求幂运算符,ab=a b)的中缀表达式,并求出结果。如果表达式正确,则输出表达式的结果;如果表达式非法,则输出错误信息。2 系统需求分析 系统目标利用栈设计一个程序,该程
3、序能够用于表达式求值,程序将读入的中缀表达式转换为后缀表达式,然后读取后缀表达式,输出结果。输入要求:程序从“”文件中读取信息,在这个文件中如果有多个中缀表达式,则每个表达式独占一行,程序的读取操作在文件的结尾处停止。输出要求:对于每一个表达式,将其结果放在“”文件的每一行中。这些结果可能是值(精确到小数点后两位),也可能是错误信息“ERROR IN INFIX NOTATION”。 主体功能能够处理以字符序列的形式输入的不含变量的实数表达式,正确处理负数与小数,判断表达式是否语法正确(包含分母不能为零的情况),正确实现对算术四则混合运算表达式的求值,能够将计算中遇到的问题和结果以文件的形式予
4、以存储。 开发环境Microsoft Visual C+ 1表达式求值3 系统概要设计 系统的功能模块划分a.判断操作数的函数判断当前所指字符是否属于数字,是就返回1,不是就返回0。b.求运算符优先级函数为了方便判断运算符优先级,先利用switch函数将不同的运算符返回不同的整型数字,在根据数字的大小判断优先级。+,-优先级相同,返回数字相同,*,/也是。c.表达式求值函数此函数是直接按照设计思路完成问题要求的函数,其中要调用到判断操作符的函数和求运算符优先级的函数。循环结束弹出栈2的数值,并返回。d.主函数main()定义一个数组存储表达式整个字符串,将返回的数值直接赋值到浮点型的结果,输出
5、结果。e.栈的函数设计栈的初始化函数charInit_SeqStackInit_SeqStack栈判空 Empty_SeqStackcharEmpty_SeqStack入栈函数 push_SeqStackcharpush_SeqStack出栈函数 Pop_SeqStackcharPop_SeqStack取栈顶函数 GetTop_SeqStackcharGetTop_SeqStack销毁栈 Destory_SeqStackcharDestory_SeqStack 系统流程图2数据结构课程设计报告(2014)图3-1 系统流程图说明:该流程图先进行算法优先级的比较,然后进行operate算法,再建
6、立栈用来存放操作字符和数据来进行计算,表达式合法就输出表达式的值,若不合法,则输出错误提示。4系统详细设计a.基本分析:在计算机中,算术表达式的计算往往是通过使用栈来实现的。所以,本表达式求值程序的最主要的数据结构就是栈。可以使用栈来存储输入表达式的操作符和操作数。输入的表达式是由操作数和运算符以及改变运算次序的圆括号连接而成的式子。算术表达式有中缀表示法和后缀表示法,本程序输入的表达式采用中缀表示法。3表达式求值在这种表达式中,二元运算符位于两个操作数中间。由于不同运算符间存在优先级,同一优先级的运算间又存在着运算结合顺序的问题,所以简单的从左到右的计算是不充分的。当然凭直观判断一个中缀表达
7、式中哪个运算符最先,哪个次之,哪个最后并不困难,但通过计算机处理就比较困难。因为计算机只能一个字符一个字符的扫描,要想知道哪个运算符先算,就必须对整个中缀表达式扫描一遍。而后缀表达式则很容易通过应用栈实现表达式的计算,这为实现表达式求值程序提供了一种直接的计算机制。b. 后缀表达式后缀表达式是由一系列的运算符、操作数组成的表达式,其中运算符位于两个操作数之后,如123*+。后缀表达式很容易通过应用栈实现表达式的计算。其基本过程是:当输入一个操作数时,它被压入栈中,当一个运算符出现时,就从栈中弹出适当数量的操作数,对该运算进行计算,计算结果在压回到栈中。对于常见的二元运算符来说,弹出的操作数只有
8、两个。处理完整个后缀表达式之后,栈顶上的元素就是表达式的结果值。整个过程不需要理解运算的优先级规则。例如,对于表达式“123*+”,起计算过程如下:1、2、3依次压入栈中,为了处理“*”,弹出栈顶的两项操作数3和2。注意:弹出的第一项为二元运算符右边的参数,第二项为左边参数;乘法运算结果是6,该值被压回到栈中去;这时,栈顶是6,其下是1.为了处理“+”运算符,6和1都要被弹出,结果7被压回到栈中。此时,表达式读取完毕,栈也只剩下一项,从而最终的答案是7.很明显,计算后缀表达式的时间是线性的。c.中缀到后缀的转换从上面分析可知,后缀表达式是很容易应用栈进行计算的,但要处理的是中缀表达式。同样,也
9、可以应用栈将中缀表达式转换为后缀表达式。此时,栈里要保存的是运算符,而在后缀表达式计算中,栈里保存的是操作数。应用栈将中缀表达式转换为后缀表达式的基本过程如下。从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理:(a)如果遇到空格,则认为是分隔符,不需处理。(b)若遇到操作数,则直接输出。(c)若是左括号,则将其压入至栈中。(d)若遇到的是右括号,表明括号的中缀表达式已经扫描完毕,把括号中的运算符退栈,并输出。(e)若遇到的是运算符,当该运算符的优先级大于栈顶运算符的优先级时,则把它压栈,当该运算符的优先级小于等于栈顶运算符时,将栈顶运算符退栈并输出,再比较新的栈顶运算符,按同样处理
10、方法,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈。(f)若中缀表达式处理完毕,则要把栈中存留的运算符一并输出。上述处理过程的一个关键是不同运算符优先级的设置。在程序实现中,可以用一个4数据结构课程设计报告(2014)数来代表运算符的优先级,优先级数值越大,它的优先级越高。这样的优先级的比较就转化为两个数大小的比较。程序的整体算法过程分为两步:第一步:从“”文件中读取中缀表达式,并应用运算符栈OpHolder 把中缀表达式转换为后缀表达式,将输出结果(转换后得到的后缀表达式)存放在一个temp文件中。第二步:从temp文件中读取后缀表达式,并应用操作数栈Operands计算后缀表达
11、式结果,结果输出到“”文件中。本程序中的栈采用前面所述的带头节点的链式存储结构,涉及两种类型:用于存储运算符号的char类型的链栈以及用于存储操作数的float类型的链栈。本程序将整个求值过程分解为两个步骤:中缀表达式转换为后缀表达式、计算后缀表达式结果值。其实,可以将这两个过程统一合并在一起完成,当然也同样需要操作数和运算法这两类栈。本程序的输入形式是“”文件,输出结果存放到“”文件中。在输入文件中等式的格式必须是中缀格式。本程序将读入的中缀表达式转换为后缀表达式,并存放在文件中;随后从中读取后缀表达式,并将计算结果输出到中一个char类型的栈“Whereat”用来记录后缀表达式中操作数和运
12、算符号的顺序,以决定需要多少次计算。5测试 测试方案设计针对程序的文件,并将运行结果与期望测试进行比较。 测试结果1.基本测试:在input文件中输入表达式如下5-1:则程序运行的输出结果如下图5-2:5表达式求值6图5-1 基本测试Input 文件 图5-2 基本测试Output 文件说明:期望值依次是,程序运行的结果与期望的值达到一致。2.扩展测试:在Input 文件中输入表达式如下图5-3: 则程序运行的结果如下图5-4:图5-3 扩展测试Input 文件 图5-4 扩展测试Output 文件说明:期望值依次是,程序运行的结果与我所期望的值达到一致。3.容错测试:在input 文件中输入
13、表达式如图5-5: 则程序运行的结果如图5-6:图5-5容错测试Input文件图5-6容错测试Output文件说明:它的期望值都是Error in infix notation.,与期望值达到一致。6 小结经过一个星期的课程设计,每天都对着电脑查阅资料,让我觉得自己知道的多么渺小。但也因为这次的课程设计,让我知道细心与耐心也是必不可少的,只有具备这两样才能做好一样事情。课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。通过这次课程设计让我对栈有了更深的理解。这次的课程设计题目要求不仅要求对课本知识有深刻的了解,
14、同时要求我们有较强的思维和动手能力。在这次程序设计中,我老是犯一些错误,使得程序编译不出来,导致后面的工作无法进行。但我们也不要怕遇到错误,在实际操作过程中犯的一些错误还会有意外的收获。在这次程序设计中我对这学期所学的栈的应用的理论知识得到巩固,实现了课程设计的目的,在这次课程设计中,我也发现了我的不足之处,我对一些看似简单的东西掌握不够熟练,需要进一步掌握。所以我们在写程序时要有足够的耐心与细心,还必须要养成好习惯,不然程序会变得杂乱无章,是我们阅读起来非常难,而且还容易出错,导致正确率降低。随意一个好的习惯是十分可取的。在课程设计中,应该使得算法简明易懂,而易于转换为上机程序;如果程序反复
15、多次使用,则应该尽可能选用快速的算法;如果待解决的问题数据量极大,机器的存储空间较小,则在编写算法时应该考虑如何节省空间。以后在编写程序时就应该注意到所编写程序的时间复杂度,以及是否运用了良好的算法,而不能只是像以前编写程序时单纯使用C语言的知识,要充分考虑程序的性能,争取编写出更优良的程序。通过这次课程设计,让我对数据结构有了更深的理解。我明白了理论与实际应用相结合的重要性,并提高了自己组织数据及编写大型程序的能力。培养了基本的、良好的程序设计技能以及合作能力。这次课程设计同样提高了我的综合运用所学知识的能力。我觉得数据结构的代码都有相似点,通用的结构,相似的格式。只要努力去学习,相信就会有
16、收获。在这一周中,我学到了很多的知识,提高了我综合运用本课程所学知识的能力,培养了我查阅资料以及文献的能力,还培养了我独立思考,分析问题的能力。通过这次的设计,让我们提高了自己的能力,还增进了组员之间的友谊与默契度。团结协作才是我们成功的一项重要保证。参考文献1胡学刚.算法与数据结构算法设计指导M.北京:清华大学出版社,19992 严蔚敏.据结构(C语言版)M.北京:清华大学出版社,20043 许卓群,杨冬青,唐世渭,张铭.数据结构与算法M.北京:高等教育出版社, 20044 张选平,雷咏梅.数据结构M.北京:机械工业出版社,20025 唐策善,黄刘生.数据结构M.北京:中国科学技术大学出版社
17、,19926 曹新谱.算法设计与分析M.长沙:湖南大学技术出版社,19847 徐孝凯.数据结构实用教程(第二版)M.北京:清华大学出版社,20068 张乃孝.算法与数据结构-C语言描述M.北京:高等教育出版社,2002附录附录1 源程序清单#include #include #include int PrintError = 0;/*全局变量,0代表正常,1代表表达式出错*/*char类型链表式堆栈,用来存放运算符号,以及用在中缀表达式转换等时候*/ typedef struct Node *PtrToNode;typedef PtrToNode Stack;int IsEmpty(Stack
18、 S);void MakeEmpty(Stack S);void Push(char X,Stack S);char Top(Stack S);void Pop(Stack S);typedef struct Nodechar Element;PtrToNode Next;/*float类型链表式堆栈,用来存放操作数*/typedef struct FNode *Ptr_Fn;typedef Ptr_Fn FStack;int FisEmpty(FStack S);void FPush(float X,FStack S);float FTop(FStack S);void FPop(FStac
19、k S);typedef struct FNodefloat Element;Ptr_Fn Next;void ConvertToPost(FILE *In, Stack Whereat,FILE *Temp);void Reverse(Stack Rev);void Calculate(FILE *Change, Stack Whereat,FILE *Temp);/*主函数*/int main()FILE *InputFile, *OutputFile,*Temp; /*初始化变量*/Stack Whereat;char sample;InputFile = fopen(OutputFil
20、e = fopen(Whereat = malloc(sizeof(struct Node); /*给Whereat分配空间*/ Whereat-Next = NULL;if (!InputFile | !OutputFile) /*错误处理*/ printf(return(1);sample = getc(InputFile);while ( sample != EOF)Temp = fopen(ungetc(sample,InputFile); /* put back sample字符*/ConvertToPost(InputFile,Whereat,Temp); /*中缀变后缀*/if
21、(PrintError) /*错误处理*/fprintf(OutputFile,fscanf(InputFile,PrintError = 0;else if (IsEmpty(Whereat) = 1) /*跳过在input文件中的空格*/else if (IsEmpty(Whereat) != 1)Reverse(Whereat);if (Top(Whereat) = B) /*错误处理,*/*A表示操作数B表示运算符*/PrintError = 1; /*后缀表达式第一个元素应是操作数而不是运算符号*/fclose(Temp);Temp = fopen(Calculate(OutputF
22、ile, Whereat,Temp); /*计算结果*/fclose(Temp);MakeEmpty(Whereat); /* 清空Whereat用来处理下一行*/putc(n,OutputFile); /* 在输出文件中换行*/sample = getc(InputFile); /* While循环结束*/free(Whereat);fclose(InputFile);fclose(OutputFile);remove(return 1;/*检查堆栈是否为空*/int IsEmpty(Stack S)return(S-Next=NULL);/*检查float堆栈是否为空*/int FIsEm
23、pty(FStack S)return(S-Next=NULL);/*弹出栈顶元素*/void Pop(Stack S)PtrToNode FirstCell;if (IsEmpty(S)perror(elseFirstCell = S-Next;S-Next = S-Next-Next;free(FirstCell);/*弹出float栈顶元素*/void FPop(FStack S)Ptr_Fn FirstCell;if (FIsEmpty(S)perror(elseFirstCell = S-Next;S-Next = S-Next-Next;free(FirstCell);/*将堆栈置
24、空*/void MakeEmpty(Stack S)if (S = NULL)perror(elsewhile (!IsEmpty(S)Pop(S);/*将float堆栈置空*/void FMakeEmpty(FStack S)if (S = NULL)perror(elsewhile (!IsEmpty(S)Pop(S);/*元素进栈*/void Push(char X, Stack S)PtrToNode TmpCell;TmpCell = (PtrToNode)malloc(sizeof(struct Node);if (TmpCell = NULL)perror(elseTmpCell
25、-Element = X;TmpCell-Next = S-Next;S-Next = TmpCell;/*float元素进栈*/void FPush(float X, FStack S)Ptr_Fn TmpCell;TmpCell = (Ptr_Fn)malloc(sizeof(struct FNode);if (TmpCell = NULL)perror(elseTmpCell-Element = X;TmpCell-Next = S-Next;S-Next = TmpCell;/*返回栈顶元素*/char Top(Stack S)if (!IsEmpty(S)return S-Next-
26、Element;perror(exit(1);return 0;/*返回float栈顶元素*/float FTop(FStack S)if (!FIsEmpty(S)return S-Next-Element;perror(exit(1);return 0;/*将堆栈元素倒置*/void Reverse(Stack Rev)Stack Tempstack;Tempstack = malloc(sizeof(struct Node);Tempstack-Next = NULL;while (!IsEmpty(Rev)Push(Top(Rev),Tempstack); /*将元素压栈到一个临时堆栈
27、*/Pop(Rev);Rev-Next = Tempstack-Next; /*指向新的堆栈*/*Whereat 说明:Whereat 记录了操作数和运算符号的位置,用A和B区分。A = operand, B = operator. (例如1+2转换成12+,在whereat中的形式应该是AAB)OpHolder说明:Char类型的堆栈Opholder用来保存运算符号。*/*将中缀表带式转换为后缀表达式*/void ConvertToPost(FILE *In, Stack Whereat, FILE *Temp)Stack OpHolder;char holder;char lastseen;int digitcounter = 0; /*操作数的计数器*/OpHolder = malloc(sizeof(struct Node); /*初始化*/OpHolder-Next = NULL;holder=getc(In);lastseen = ; /*用来防止输入格式错误,例如两个小数点*/putc( ,Temp);whil
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1