1、 输入:6+9-5 输出:10 b.乘除运算5.6*2.7/2 输出:7.56 c.四则混合运算(2+3)*8-3/2 输出:23.5 d.非法输入(5+6(*5 输出:括号不匹配! 1.2问题分析与之前利用栈实现计算器功能不同,本实验采取的方法是:将中缀表达式转换成一棵二叉表达式树,通过对该树的后序遍历求出计算表达式的值。所以,实验的重点是如何“将中缀表达式转换成一棵二叉表达式树”;如上图所示,该二叉表达式树表示的是计算式(5+2)*3。可以看出,操作数均为叶子结点,其它结点为操作符;构建二叉树的整体思路是:(1)将中缀表达式转化为后缀表达式;(2)利用(1)中的后缀表达式,在此基础上构建二
2、叉表达式树。最后的求值,可以通过递归调用函数,后序遍历二叉树来完成。二、概要设计2.1抽象数据类型定义 本程序主要用到的数据结构是二叉链表,所以先行定义链表结点,其中每一个节点包含两个数据域和两个指针域,数据域分别存放char型变量和float型变量,相对应是运算符和操作数;指针域分别指向两个左右孩子。 struct node char data; float number; struct node *left; struct node *right; ;另外,考虑到程序还需转换后缀表达式,所以又建立了另一种结点类型变量,并定义其类型的数组array20: struct oprtnumber
3、char sign; /存放符号型变量 /存放浮点数 array20;2.2主程序流程主函数流程如下: int main() char *b,a100,*t; b=convert(); /中缀表达式转为反序后缀表达式 do 完成反序后缀式的逆向 ; T=create(T,a); /create()函数创建二叉链表 postordertraverse(T);/后序遍历进行计算 输出结果; /main2.3程序模块调用关系 具体关系如下图所示:三、详细设计3.1主函数的具体过程 int main() struct node *T; flag=0; T=(struct node *)malloc(s
4、izeof(struct node); int i; b=convert(); for(t=b;*t!=0;t+); i=0; t-; ai=*t; i+; while(t!=b); ai=/完成反序后缀式的逆向 postordertraverse(T);printf(%g,result); /输出结果 return 0;3.2其它函数的具体实现char *convert();/将运算式转换成逆后缀序列,并将该序列作为返回值;首先输入运算式,判断是否为数字,将数字存入数组的数值域,并用符号代替数值,产生新的用符号表示的运算式。然后用字符优先算法将算式转换为逆后缀式,将数组首地址传回给主函数。并
5、且在输入不合法时给予错误提示。struct node *create(struct node *T,char d);/建立二叉链表,并返回根结点 void postordertraverse(struct node *e);/进行后序遍历,运用了递归的思想,实际上调用operation函数进行计算 float operation(float a,float b,char c); /四则运算函数,主要实现运算功能 int in(char c); /判断是否为运算符,是运算符返回1 部分函数的代码如下:(1)create函数struct node *create(struct node *T,ch
6、ar d) /建立二叉链表,并返回根结点 int i; if(dwA&dwdata=dw; for(i=0;arrayi.sign!i+) if(arrayi.sign=dw) T-number=arrayi.number;break; T-left=NULL; T-right=NULL; w+; else if(flag=0)flag=1; else T=(struct node *)malloc(sizeof(struct node ); (T)- w+;left=(struct node *)malloc(sizeof(struct node );right=(struct node *
7、)malloc(sizeof(struct node );right=create(T)-right,d);left=create(T)-left,d); return T; /create(2)operation函数float operation(float a,float b,char c) /四则运算函数,主要实现运算功能 switch(c) case +:return a+b;-return a-b;*return a*b;/return a/b; default :运算符错误!n); exit(0); /operation(3)in函数int in(char c) /判断是否为运算符
8、,是运算符返回1;否则返回0 if(c=|c=() return 1; else return 0; /in四、调试分析4.1难点以及困难1.由于本次试验做过堆栈式计算器,思维存在惯性,打不开新思路;2.建立二叉链表是最重要的环节,而在这之前,必须先得到后缀表达式,由于之前没有接触过后缀表达式,从而给变成造成了困难。即涉及char型和float型变量统一化,又有算符优先级的判别。3.二叉链表的建立,要利用好优先级,以及注意操作数为叶子节点这一特点。4.2经验与体会1.算式计算的问题是一个非常经典的题目。之前用栈来实现的。但是用栈来实现是一个非常麻烦的过程,第一要解决算式判断,是否为符合规则的算
9、式,第二要由中缀表达式转化为后缀表达式。这两个部分是栈实现计算算式表达式的比较复杂的地方。不仅如此,栈实现里面的各种运算符的优先级,各种条件判断,可以说是麻烦的要命。相比之下,用二叉树免除了算式表达式的检查过程。并不是不需要检查,而是检查的过程就包含在创建二叉树的过程。认真分析,我们会发现,所有的叶子结点必须是操作数结点,而所有的非叶子结点必须是运算符结点,否则表达式的结构一点不正确,创建二叉树的过程就可以对表达式经行检查。2.总结一句就是:好的数据结构能事半功倍,要培养善于发现的思维,当有某个思路然后去实现它,另外要积累经验。好好理解数据结构!五、测试结果1.加减运算输入:2.乘除运算3.四
10、则混合运算4.非法输入六、附录#includestring.hstdlib.hmath.hstruct node struct oprtnumber /*函数声明*/ char *convert();/将运算式转换成逆后缀序列 struct node *create(struct node *T,char d);/建立二叉链表 void postordertraverse(struct node *e);/进行后序遍历 /四则运算函数 /判断是否为运算符,是运算符返回1 /*定义全局变量*/ int w,flag; float result=0; float operation(float a,float b,char c) switch(c) struct node *create(struct node *T,char d) int i;data=d
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1