1、数据结构课程设计报告题目:表达式类型的实现(难度系数:1.2)学 院 计算机 专 业 计算机科学与技术 年级班别 2015 级 8 班 学 号 3115005210 学生姓名 杨嘉慧 指导教师 李杨 编 号 成 绩 2017 年 1 月报告:报告内容: 详细 完整 基本完整 不完整设计方案: 非常合理 合理 基本合理 较差算法实现: 全部实现 基本实现 部分实现 实现较差测试样例: 完备 比较完备 基本完备 不完备文档格式: 规范 比较规范 基本规范 不规范答辩:理解题目透彻,问题回答流利理解题目较透彻,回答问题基本正确部分理解题目,部分问题回答正确未能完全理解题目,答辩情况较差总评成绩:优
2、良 中 及格 不及格运行环境:CodeBlocks完成的题目:表达式类型的实现(难度系数:1.2)选做的内容:(4)在表达式内增加对三角函数等初等函数的操作。一、 需求分析【课程设计要求】 【问题的描述】 一个表达式和一棵二叉树之间,存在着自然的对应关系。写一个程序,实现 基于二叉树表示的算术表达式 Expression 的操作。 【基本要求】 【一】【必做部分】 假设算术表达式 Expression 内可以含有变量(a-z),常量(0-9)和二元运算符(+,-,*,/,(乘幂)。实现以下操作: (1)ReadExpr(E)以字符序列的形式输入语法正确的前缀表达式并构造表达式 E。 (2)Wr
3、iteExpr(E)用带括号的中缀表达式输出表达式 E。 (3)Assign(V,c)实现对变量 V 的赋值(V=c),变量的初值为 0。 (4)Value(E)对算术表达式 E 求值。 (5)CompoundExpr(p,E1,E2)构造一个新的复合表达式(E1)p(E2)。【二】【选做部分】 (1)以表达式的原书写形式输入,支持大于 0 的正整数常量; (2)增加常数合并操作 MergeConst(E)合并表达式 E 中所有常数运算。例如,对表达式 E=(2+3-a)*(b+3*4)进行合并常数的操作后,求得 E=(5-a)*(b+12)(3)增加对求偏导数的运算 Diff(E,V)求表达
4、式 E 对 V 的导数 (4)在表达式内增加对三角函数等初等函数的操作。 【测试数据】 (1)分别输入 0;a;-91;+a*bc;+*5x2*8x;+*3*2x2x6 并输出。 (2)每当输入一个表达式后,对其中的变量赋值,然后对表达式求值。 二、【概要设计】 1、数据类型的声明: 在这个课程设计中,采用了链表二叉树的存储结构,以及两个顺序栈的辅助存储结构/*头文件以及存储结构*/#include #include #include #include #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0typedef int
5、Status;2、表达式的抽象数据类型定义 基本操作:void judge_str( 操作结果:运算符运算求值,参数 opr1,opr2 为常量,opr 为运算符,根据不同的运算符,实现不同的运算,返回运算结果。 Status Check(E) 初始条件:表达式 E 存在; 操作结果:检查表达式 E 是否还存在没有赋值的变量,以便求算数表达式 E的值。 long Value(E) 初始条件:表达式 E 存在; 操作结果:对算术表达式求值,返回求到的结果。 void CompoundExpr(P,/*INT 为整型数据 num,CHAR 为字符型数据 c*/ typedef struct TEl
6、emType ElemTag tag;/*INT,CHAR指示是整型还是字符型*/ union int num;/*tag=INT 时,为整型*/ char c;/*tag=CHAR 时,为字符型*/ ; TElemType; /*二叉树的二叉链表存储表示 */ typedef struct BiTNode TElemType data; struct BiTNode *lchild,*rchild; /* 左右孩子指针 */ BiTNode,*BiTree; 二叉树的基本操作已经在构造表达式和表达式中的基本操作中根据不同的功能和实际 情况修改了,详细见各个函数操作的算法设计。 主程序模块二叉
7、树模块顺序栈 SqStack 模块2、顺序栈的存储类型 /*栈的顺序存储表示 */ #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */ #define STACKINCREMENT 2 /* 存储空间分配增量 */ /*顺序栈*/ typedef struct SqStack SElemType *base; /* 在栈构造之前和销毁之后,base 的值为 NULL */ SElemType *top; /* 栈顶指针 */ int stacksize; /* 当前已分配的存储空间,以元素为单位*/ SqStack; /* 顺序栈 SqStack */3、表达
8、式的基本操作 Status Input_Expr(char *string,int flag); /*以字符序列的形式输入语法正确的前缀表达式,保存到字符串 string*/ /*参数 flag=0 表示输出的提示信息是“请输入正确的前缀表示式:“*/ /*flag=1 表示输出的提示信息为“请以表达式的原书写形式输入正确表示式:“*/ void judge_str(BiTree *E,char *string,int i); /*判断字符 stringi,如果是0-9常量之间,二叉树结点存为整型;否则,存为字符型*/ Status Pri_Compare(char c1,char c2);
9、/*如果两个字符是运算符,比较两个运算符的优先级,c1 比 c2 优先,返回OK,否则返回 ERROR*/ void WriteExpr(BiTree E); /*用带括弧的中缀表达式输入表达式*/ void Assign(BiTree *E,char V,int c,int *flag); /*实现对表达式中的所有变量 V 的赋值(V=c),参数 flag 为表示是否赋值过的标志*/ long Operate(int opr1,char opr,int opr2); /*运算符运算求值,参数 opr1,opr2 为常量,opr 为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/ S
10、tatus Check(BiTree E); /*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/ long Value(BiTree E); /*对算术表达式求值*/ void CompoundExpr(char P,BiTree *E1,BiTree E2); /*构造一个新的复合表达式*/4、主程序和其他伪码算法void main()BiTree E1,E2;char V,P;int c;ReadExpr(printf(“nE1 带括弧的中缀表示式为:“);WriteExpr(E1);while(Check(E1)=TRUE)printf(“n 请输入要赋值的字符:“);V=
11、getchar();printf(“请输入要将赋值为:“);scanf(“%d“,Assign(getchar();WriteExpr(E1);printf(“n 输入未知数后 E1 表达式为:“);WriteExpr(E1);printf(“nE1 表达式的值为: %d“,Value(E1);ReadExpr(printf(“nE2 带括弧的中缀表示式为:“);WriteExpr(E2);Assign(CompoundExpr(P,5、函数的调用关系除了主函数 main()外,其他各个函数相对于其它函数来说是独立的,函数的使用都由主函数 main()调用使用的,可以简单的说,各个函数都是主函
12、数下的从函数。四、【调试分析】1. 开始设计时我设想建树时可以设定五个域,左右孩子,标志tag, int 型值域,char 型值域。但是在存储时发现每个字符只需占一个域就可以,所以我又采用共同体这样节约了内存。2. 在算法设计中,构造表达式树的时候,本来以为使用递归构造表达式会很难做到出错处理的,所以采用了顺序栈辅助构造方法,并且尽可能地对程序进行完善,出错处理。但是经过与同学的相互讨论和研究,发现自己的想法犯了很大的错误,递归构造表达式对于出错处理很简单也很完善,这一点让我加深了递归的使用和理解。3.也就是三角函数问题,我最头疼的地方。首先开始运行时会出现错误,无法输出正确结果。通过网上搜索
13、,我发现对于三角函数的定义类型必须是double,这样的话,如果要改的话,差不多改大半程序,所以我就让此功能单独出来,由提示让用户手动完成。4.在调试的过程中,花费时间最为多的是对输入错误表达式的出错处理,更改增加的代码几乎都是为了出错处理,但是,觉得这样的调试才更能锻炼一个人的编程能力。五、【用户使用说明】打开程序,按屏幕上的提示输入数据,随后就可以看到结果了。六、【测试结果】1.输入 02.输入 a3.输入-914.输入+a*bc5.输入+*5x2*8x6.输入+*3x3*2x2x67. CompoundExpr(P,typedef enumINT,CHARElemTag;typedef
14、struct TElemType ElemTag tag;union int num;char c;TElemType;typedef struct BiTNode TElemType data;struct BiTNode *lchild,*rchild;BiTNode,*BiTree;typedef BiTree SElemType;#define STACK_INIT_SIZE 10#define STACKINCREMENT 2typedef struct SqStack SElemType *base;SElemType *top;int stacksize;SqStack;Stat
15、us InitStack(SqStack *S) (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType);if(!(*S).base)exit(OVERFLOW);(*S).top=(*S).base;(*S).stacksize=STACK_INIT_SIZE;return OK;Status StackEmpty(SqStack S) if(S.top=S.base)return TRUE;elsereturn FALSE;Status Push(SqStack *S,SElemType e) if(*S).top-(
16、*S).base=(*S).stacksize)(*S).base=(SElemType *)realloc(*S).base,(*S).stacksize+STACKINCREMENT)*sizeof(SElemType); if(!(*S).base)exit(OVERFLOW);(*S).top=(*S).base+(*S).stacksize;(*S).stacksize+=STACKINCREMENT;*(*S).top)+=e;return OK;Status Pop(SqStack *S,SElemType *e) if(*S).top=(*S).base)return ERRO
17、R;*e=*-(*S).top;return OK;Status GetTop(SqStack S,SElemType *e)if(S.topS.base) *e=*(S.top-1);return OK;else return ERROR; void judge_str(BiTree *E,char *string,int i)if(stringi=0(*E)-data.num=stringi-48;else(*E)-data.tag=CHAR;(*E)-data.c=stringi;Status ReadExpr(BiTree *E)SqStack S;int i,len;BiTree p
18、,q;(*E)=(BiTree)malloc(sizeof(BiTNode);(*E)-lchild=NULL;(*E)-rchild=NULL;char string150;printf(“n 请输入语法正确的前缀表示式:“);gets(string1);len=strlen(string1);if(len=1)judge_str(E,string1,0);else judge_str(E,string1,0);InitStack(q=(*E);Push(Push(for(i=1;ilchild=NULL;p-rchild=NULL;if(string1i=+|string1i=-|stri
19、ng1i=*|string1i=/|string1i=) if(!q-lchild) q-lchild=p;Push(q=p;else q-rchild=p;Push(q=p;elseif(!q-lchild) q-lchild=p;Pop(else q-rchild=p;Pop(if(StackEmpty(S)elseprintf(“n 输入的表达式有误!“);return ERROR;Status Pri_Compare(char c1,char c2) if(c1=|c1=*|c1=-|c1=+|c1=/)else return ERROR;else if(c1=*|c1=/)if(c2
20、=|c2=*|c2=/) return ERROR;else return OK;else return ERROR;else return ERROR;void WriteExpr(BiTree E) if(E)if(E-lchildWriteExpr(E-lchild);printf(“)“);else WriteExpr(E-lchild);else WriteExpr(E-lchild);if(E-data.tag=INT)printf(“%d“,E-data.num);else printf(“%c“,E-data.c);if(E-rchildWriteExpr(E-rchild);
21、printf(“)“);else WriteExpr(E-rchild);else WriteExpr(E-rchild);Status Check(BiTree E)if(Ereturn TRUE;if(!Check(E-lchild)Check(E-rchild);void Assign(BiTree *E,char V,int c)if(*E)if(*E)-data.tag=CHAR(*E)-data.num=c;Assign(Assign(long power(int x,int exp)long result;int i;for(i=1,result=1;ilchildreturn
22、Operate(Value(E-lchild),E-data.c,Value(E-rchild);void CompoundExpr(char P,BiTree *E1,BiTree E2)BiTree E;printf(“n 请输入根结点的值:“);P=getchar();E=(BiTree)malloc(sizeof(BiTNode);E-data.tag=CHAR;E-data.c=P;E-lchild=(*E1);E-rchild=E2;(*E1)=E;printf(“n 表达式 E 复合成功!其表达式变为:n“);WriteExpr(E);void main()BiTree E1,E
23、2;char V,P;int c;ReadExpr(printf(“nE1 带括弧的中缀表示式为:“);WriteExpr(E1);while(Check(E1)=TRUE)printf(“n 请输入要赋值的字符:“);V=getchar();printf(“请输入要将赋值为:“);scanf(“%d“,Assign(getchar();WriteExpr(E1);printf(“n 输入未知数后 E1 表达式为:“);WriteExpr(E1);printf(“nE1 表达式的值为: %d“,Value(E1);ReadExpr(printf(“nE2 带括弧的中缀表示式为:“);WriteExpr(E2);Assign(CompoundExpr(P,八、【心得体会】1 经过这两周的编译,我感觉对二叉树的掌握更牢固了,整体上我都是用的二叉树处理实现各个功能。我感觉对于一个题目中处理函数尽量让他可以多功能中使用,这样编程效率会高一些。 2. 我开始设计的时候只考虑一个功能一个功能的实现。这样做很没有全局观念。我认为在以后的编程中一定要有全局意识,整体上构思好,有个好的数据结构,这样事半功倍。3.编程就是要多动手。