数据结构课程设计表达式类型的实现难度系数12文档格式.docx
《数据结构课程设计表达式类型的实现难度系数12文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计表达式类型的实现难度系数12文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
【一】【必做部分】
假设算术表达式Expression内可以含有变量(a-z),常量(0-9)和二元运算符(+,-,*,/,^(乘幂))。
实现以下操作:
(1)ReadExpr(E)――以字符序列的形式输入语法正确的前缀表达式并构造表达式E。
(2)WriteExpr(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)——求表达式E对V的导数
【测试数据】
(1)分别输入0;
a;
-91;
+a*bc;
+*5x2*8x;
+++*3^*2^x2x6并输出。
(2)每当输入一个表达式后,对其中的变量赋值,然后对表达式求值。
二、【概要设计】
1、数据类型的声明:
在这个课程设计中,采用了链表二叉树的存储结构,以及两个顺序栈的辅助存储结构
/*头文件以及存储结构*/
#include<
stdio.h>
conio.h>
stdlib.h>
string.h>
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
typedefintStatus;
2、表达式的抽象数据类型定义
基本操作:
voidjudge_str(&
E,&
string1)
初始条件:
树E存在,表达式的前缀字符串string存在;
操作结果:
判断字符string[i],如果是'
0'
-'
9'
常量之间,二叉树结点E存为整型;
否则,存为字符型。
StatusReadExpr(&
表达式的前缀形式字符串exprstring存在;
以正确的前缀表示式exprstring并构造表达式E,构造成功,返回OK,否则返回ERROR。
StatusPri_Compare(c1,c2)
c1和c2是字符;
如果两个字符是运算符,比较两个运算符的优先级,c1比c2优先,返回OK,否则返回ERROR。
voidWriteExpr(&
E)
表达式E存在;
操作条件:
用带括弧的中缀表达式输入表达式E。
voidAssign(&
E,V,c)
表达式E存在,flag为标志是否有赋值过;
实现对表达式E中的所有变量V的赋值(V=c)。
longOperate(opr1,opr,opr2)
操作数opr1和操作数opr2以及操作运算符opr;
运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果。
StatusCheck(E)
检查表达式E是否还存在没有赋值的变量,以便求算数表达式E的值。
longValue(E)
对算术表达式求值,返回求到的结果。
voidCompoundExpr(P,&
E1,E2)
表达式E1和E2存在;
构造一个新的复合表达式(E1)P(E2)。
3、整体设计
在这个课程设计中,有一个源代码文件:
expression.c。
在expression.c文件中,是实现课程设计要求的各个函数。
主程序的流程以及各程序模块之间的调用关系:
1、各个存储结构的声明;
2、顺序栈的基本操作。
其基本操作如下:
对于栈SqStack:
StatusInitStack(SqStack*S)/*构造一个空栈S*/
StatusStackEmpty(SqStackS)/*若栈S为空栈,则返回TRUE,否则返回FALSE*/
StatusPush(SqStack*S,SElemTypee)/*插入元素e为新的栈顶元素*/
StatusPop(SqStack*S,SElemType*e)/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;
否则返回ERROR*/
StatusGetTop(SqStackS,SElemType*e)/*若栈不空,则用e返回S的栈顶元素,并返回OK;
3、本程序有三个模块,主程序模块,二叉树模块,一个个顺序栈模块。
三者者的调用关系如下:
三、【详细设计】
1、二叉树的存储类型/*二叉树结点类型*/
typedefenum{INT,CHAR}ElemTag;
/*INT为整型数据num,CHAR为字符型数据c*/
typedefstructTElemType
{ElemTagtag;
/*{INT,CHAR}指示是整型还是字符型*/
union{
intnum;
/*tag=INT时,为整型*/
charc;
/*tag=CHAR时,为字符型*/
};
}TElemType;
/*二叉树的二叉链表存储表示*/
typedefstructBiTNode{
TElemTypedata;
structBiTNode*lchild,*rchild;
/*左右孩子指针*/}BiTNode,*BiTree;
二叉树的基本操作已经在构造表达式和表达式中的基本操作中根据不同的功能和实际情况修改了,详细见各个函数操作的算法设计。
2、顺序栈的存储类型/*栈的顺序存储表示*/
#defineSTACK_INIT_SIZE10/*存储空间初始分配量*/
#defineSTACKINCREMENT2/*存储空间分配增量*/
/*顺序栈*/
typedefstructSqStack{
SElemType*base;
/*在栈构造之前和销毁之后,base的值为NULL*/SElemType*top;
/*栈顶指针*/
intstacksize;
/*当前已分配的存储空间,以元素为单位*/
}SqStack;
/*顺序栈SqStack*/
3、表达式的基本操作
StatusInput_Expr(char*string,intflag);
/*以字符序列的形式输入语法正确的前缀表达式,保存到字符串string*//*参数flag=0表示输出的提示信息是"
请输入正确的前缀表示式:
"
*//*flag=1表示输出的提示信息为"
请以表达式的原书写形式输入正确表示式:
*/
voidjudge_str(BiTree*E,char*string,inti);
/*判断字符string[i],如果是'
常量之间,二叉树结点存为整型;
否则,存为字符型*/
StatusPri_Compare(charc1,charc2);
/*如果两个字符是运算符,比较两个运算符的优先级,c1比c2优先,返回OK,否则返回ERROR*/
voidWriteExpr(BiTreeE);
/*用带括弧的中缀表达式输入表达式*/voidAssign(BiTree*E,charV,intc,int*flag);
/*实现对表达式中的所有变量V的赋值(V=c),参数flag为表示是否赋值过的标志*/
longOperate(intopr1,charopr,intopr2);
/*运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/StatusCheck(BiTreeE);
/*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/
longValue(BiTreeE);
/*对算术表达式求值*/
voidCompoundExpr(charP,BiTree*E1,BiTreeE2);
/*构造一个新的复合表达式*/
4、主程序和其他伪码算法
voidmain(){
BiTreeE1,E2;
charV,P;
intc;
ReadExpr(&
E1);
printf("
\nE1带括弧的中缀表示式为:
);
WriteExpr(E1);
while(Check(E1)==TRUE){
\n请输入要赋值的字符:
V=getchar();
请输入要将赋值为:
scanf("
%d"
&
c);
Assign(&
E1,V,c);
getchar();
\n输入未知数后E1表达式为:
}
\nE1表达式的值为:
%d"
Value(E1));
E2);
\nE2带括弧的中缀表示式为:
WriteExpr(E2);
E2,V,c);
CompoundExpr(P,&
E1,E2);
5、函数的调用关系
除了主函数main()外,其他各个函数相对于其它函数来说是独立的,函数的使用都由主函数main()调用使用的,可以简单的说,各个函数都是主函数下的从函数。
四、【调试分析】
1.
开始设计时我设想建树时可以设定五个域,左右孩子,标志tag,
int型值域,char型值域。
但是在存储时发现每个字符只需占一个域就可以,所以我又采用共同体这样节约了内存。
2.
在算法设计中,构造表达式树的时候,本来以为使用递归构造表达式会很难做到出错处理的,所以采用了顺序栈辅助构造方法,并且尽可能地对程序进行完善,出错处理。
但是经过与同学的相互讨论和研究,发现自己的想法犯了很大的错误,递归构造表达式对于出错处理很简单也很完善,这一点让我加深了递归的使用和理解。
3.也就是三角函数问题,我最头疼的地方。
首先开始运行时会出现错误,无法输出正确结果。
通过网上搜索,我发现对于三角函数的定义类型必须是double,这样的话,如果要改的话,差不多改大半程序,所以我就让此功能单独出来,由提示让用户手动完成。
4.在调试的过程中,花费时间最为多的是对输入错误表达式的出错处理,更改增加的代码几乎都是为了出错处理,但是,觉得这样的调试才更能锻炼一个人的编程能力。
五、【用户使用说明】
打开程序,按屏幕上的提示输入数据,随后就可以看到结果了。
六、【测试结果】
1.输入0
2.输入a
3.输入-91
4.输入+a*bc
5.输入+*5x2*8x
6.输入+++*3^x3*2^x2x6
7.CompoundExpr(P,&
E1,E2)合并操作
七、【附录】
math.h>
#defineTRUE1
#defineFALSE0
#defineOK1
typedefstructTElemType{
ElemTagtag;
union{
};
}TElemType;
typedefstructBiTNode{
}BiTNode,*BiTree;
typedefBiTreeSElemType;
#defineSTACK_INIT_SIZE10
#defineSTACKINCREMENT2
typedefstructSqStack{
SElemType*top;
}SqStack;
StatusInitStack(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;
returnOK;
}
StatusStackEmpty(SqStackS){
if(S.top==S.base)
returnTRUE;
else
returnFALSE;
StatusPush(SqStack*S,SElemTypee){
if((*S).top-(*S).base>
=(*S).stacksize){
(*S).base=(SElemType*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));
(*S).top=(*S).base+(*S).stacksize;
(*S).stacksize+=STACKINCREMENT;
*((*S).top)++=e;
StatusPop(SqStack*S,SElemType*e){
if((*S).top==(*S).base)returnERROR;
*e=*--(*S).top;
StatusGetTop(SqStackS,SElemType*e){
if(S.top>
S.base){
*e=*(S.top-1);
elsereturnERROR;
voidjudge_str(BiTree*E,char*string,inti){
if(string[i]>
='
&
string[i]<
){
(*E)->
data.tag=INT;
data.num=string[i]-48;
else{
data.tag=CHAR;
data.c=string[i];
StatusReadExpr(BiTree*E){
SqStackS;
inti,len;
BiTreep,q;
(*E)=(BiTree)malloc(sizeof(BiTNode));
lchild=NULL;
rchild=NULL;
charstring1[50];
printf("
\n请输入语法正确的前缀表示式:
gets(string1);
len=strlen(string1);
if(len==1)
judge_str(E,string1,0);
else{
InitStack(&
S);
q=(*E);
Push(&
S,q);
for(i=1;
i<
len&
!
StackEmpty(S);
i++){
p=(BiTree)malloc(sizeof(BiTNode));
judge_str(&
p,string1,i);
p->
if(string1[i]=='
+'
||string1[i]=='
*'
/'
^'
){
if(!
q->
lchild){
lchild=p;
S,p);
q=p;
rchild=p;
Pop(&
S,&
q);
if(StackEmpty(S)&
i>
=len)returnOK;
\n输入的表达式有误!
returnERROR;
}}}
StatusPri_Compare(charc1,charc2){
if((c1=='
||c1=='
)&
(c2=='
||c2=='
)){
if(c1=='
if(c2!
)returnOK;
elseif(c1=='
if(c2=='
)returnERROR;
elsereturnOK;
voidWriteExpr(BiTreeE){
if(E){
if(E->
lchild&
E->
lchild->
data.tag==CHAR){
if(Pri_Compare(E->
data.c,E->
data.c)){
("
WriteExpr(E->
lchild);
)"
elseWriteExpr(E->
data.tag==INT){printf("
E->
data.num);
elseprintf("
%c"
data.c);
rchild&
rchild->
rchild);
}}
StatusCheck(BiTreeE){
if(E&
data.c!
\n表达式中仍存在变量没有赋值!
没法求出表达式的值!
Check(E->
lchild))Check(E->
voidAssign(BiTree*E,charV,intc){
if(*E){
if((*E)->
data.tag==CHAR&
data.c==V){
data.num=c;
;
Assign(&
((*E)->
lchild),V,c);
rchild),V,c);
longpower(intx,intexp){
longresult;
inti;
for(i=1,result=1;
=exp;
i++)
result*=x;
returnresult;
longOperate(intopr1,charopr,intopr2){
switch(opr){
case'
:
result=opr1+opr2;
break;
result=opr1-opr2;
result=opr1*opr2;
result=opr1/opr2;
result=power(opr1,opr2);
default:
}}
doubleOperate1(charopr,doubleopr1){
doubleresult1;
~'
/*正玄sin*/result1=sin(opr1);
returnresult1;
'
/*余弦*/result1=cos(opr1);
@'
/*正切*/result1=tan(opr1);
l