题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx

上传人:b****6 文档编号:5825862 上传时间:2023-01-01 格式:DOCX 页数:34 大小:231.37KB
下载 相关 举报
题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx_第1页
第1页 / 共34页
题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx_第2页
第2页 / 共34页
题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx_第3页
第3页 / 共34页
题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx_第4页
第4页 / 共34页
题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx

《题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx》由会员分享,可在线阅读,更多相关《题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx(34页珍藏版)》请在冰豆网上搜索。

题目设计一个程序实现基于二叉树表示的算术表达式的操作.docx

题目设计一个程序实现基于二叉树表示的算术表达式的操作

题目:

设计一个程序实现基于二叉树表示的算术表达式的操作。

一、需求分析

1、以二叉树为基本模型,构建了表达式二叉树。

算术表达式的合法输入数据包括变量(,a~z)、常量(0-9)和二元运算符(+,-,*,/,^(乘幂)),一元运算符(sin,cos,tan)。

演示程序以人机对话的方式执行,即在计算机上显示提示信息后,由用户在键盘上输入对应的数据或命令,程序将执行相应的操作并显示下一步信息。

表达式的输出主要是用带括号的中缀表示式输出调用函数InorderExp(ExpTreeE,Status(*Visit)(ExpTreee));

2、程序的目的实现算术表达式在计算机里的树形存储,实现基本的运算(+,-,*,/,^(乘幂))sin,cos,tan),求偏导,常数合并。

3、测试数据(附后)。

提供两种方式的测试:

一种是自动测试,即程序调用test文件夹data.txt文件里的测试数据,另一种方式是手动测试,即按程序提示一步一步输入测试。

除了满足要求的0;a;-91;+a*bc;+*5^x2*8x;+++*3^x3*2^x2x6,还有几十组数据测试。

每当输入一个表达式后,程序提示用户赋值,再对表达式求值。

为了方便用户,我在程序中用数组保存着一些测试数据,以供测试用。

二、概要设计

1.以字符串保存输入的字符序列。

2.提示用户赋值的同时将数据取出建立二叉树。

3.用后根遍历的次序用递归函数对表达式求值,求值时进行相应的转化,将运算数的字符形式转换成整数形式。

4.用中缀表达式输出表达式时,适当添加括号,以正确反映运算的优先次序。

5.抽象数据类型的定义:

1)、存放表达式的结构类型,是以二叉树为基本原型。

typedefenum{OPER,VAR,ORD}ElemTag;//运算符,变量,常量

typedefstructExpNode

{

ElemTagtag;//标记

union{

charexpr[4];//存放运算符名

struct{

charvar;//存放变量名

intval;//存放变量的值,初始值为0

}vary;//存放变量

intordina;//存放常量值

};

structExpNode*lchild,*rchild;/*左右孩子指针*/

}*ExpTree;/*二叉树的二叉链表存储表示*/

基本操作:

intRandom(intnMin,intnMax);

//返回nMin到nMax之间的随机数

voidFindVary(char*c,char*e);

//找出表达式中的变量

StatusArrayCreateExp(ExpTree&E,char*ch,int&i);

//从ch数组中读取字符串,构造表达式

voidCreateExp(ExpTree&E,char*ch,int&i);

//StatusInputCreateExp(ExpTree&E);

//从键盘先序输入来构造表达式树T

StatusVisit(ExpTreee);

//输出e的内容

voidInorderExp(ExpTreeE,Status(*Visit)(ExpTreee));

//输出中序表达式用带括号的中缀表示式输出

StatusAssign(ExpTreeE,charv,floatc);

//对表达式内的所有v,赋值c

floatValue(ExpTreeE);

//计算表达式的值

ExpTreeCompound(charp,ExpTreee1,ExpTreee2);

//5.构造一个新的复合表达式(E1)P(E2)

StatusDiff(ExpTree&E,charV);

//求表达式E对变量V的导数

voidMergeConst(ExpTreeE);

//合并表达式种所有常数运算

StatusPreOrderTraverse(ExpTreeE,Status(*Visit)(ExpTreee));

//波兰式输出

StatusPostOrderTraverse(ExpTreeE,Status(*Visit)(ExpTreee));

//逆波兰式输出

2)、队列

typedefcharQElemType;

typedefstructQNode

{

QElemTypedata;

structQNode*next;

}QNode,*QuePtr;

typedefstruct

{

QuePtrfront;

QuePtrrear;

}Queue;

基本操作:

StatusInitQueue(Queue&Q);

//构造一个空队列

StatusDestroyQueue(Queue&Q);

//销毁队列

StatusQueueEmpty(QueueQ);

//判空

StatusEnQueue(Queue&Q,QElemTypee);

//插入元素e为Q的新的队尾元素

StatusDeQueue(Queue&Q,QElemType&e);

//删除队头元素,用e返回其值,并返回OK,否则返回ERROR;

3)、栈

typedefstruct

{

SElemType*base;

SElemType*top;

intstacksize;

}SqStack;

基本操作:

StatusInitStack(SqStack&S);

StatusStackEmpty(SqStackS);

StatusPush(SqStack&S,SElemTypee);

StatusPop(SqStack&S,SElemType&e);

SElemTypeTop(SqStackS);

6、主程序:

voidmain()

{

while

(1)

{接受命令

处理命令;

Switch()

{

case:

1.以数组形式输入前缀表示式函数构造表达式.

case:

2.以字符序列输入前缀表示式函数构造表达式.

case:

3.实现对变量V的赋值(V=c).

case:

4.对算术表达式E求值.\n");

case:

5.构造一个新的复合表示式(E1)P(E2).

case:

6.求偏导函数Diff(E,V)

case:

7.对三角函数的测试.

case:

8.常数合并.

case:

0.结束

}

}

三、详细设计

1、存放表达式的结构类型,是以二叉树为基本原型。

typedefenum{OPER,VAR,ORD}ElemTag;//运算符,变量,常量

typedefstructExpNode

{

ElemTagtag;//标记

union{

charexpr[4];//存放运算符名

struct{

charvar;//存放变量名

intval;//存放变量的值,初始值为0

}vary;//存放变量

intordina;//存放常量值

};

structExpNode*lchild,*rchild;/*左右孩子指针*/

}*ExpTree;/*二叉树的二叉链表存储表示*/

我原来是直接用二叉树的存储结构的,后来发现受到这个结构类型的很大限制,受到广义表存储结构的启发,就自己设计了这样一个存储类型。

下面分析这个存储结构:

(1)、用ElemTagtag;来标记是运算符,变量,常量。

用枚举类型定义typedefenum{OPER,VAR,ORD}ElemTag,可以区分是运算符,变量,常量。

(2)、用字符串charexpr[4];来存放运算符名,我先预定存放三个字符的运算符名(最后一个char用来存放’\0’),这样运算符不仅可以是'+','-','*','/','^',还可以是’sin’,’cos’,’tan’。

如果觉得三个字符不够,可以扩展。

(3)、struct{charvar;//存放变量名floatval;//存放变量的值,初始为0}vary;//存放变量。

这样在变量赋值后,还可以保存着变量名。

可以用作如公式一样,重复赋值使用。

(4)、使用intordina;来存放常量值。

这样赋值时,就扩大了赋值范围,可以是一个整形的范围,大大扩大了本程序的使用范围。

但需要在赋值时使用,在输入时,还是得用0-9,这也是本程序的缺陷,有待改进。

基本操作:

intRandom(intnMin,intnMax);

//返回nMin到nMax之间的随机数

voidFindVary(char*c,char*e);

//找出表达式中的变量

StatusArrayCreateExp(ExpTree&E,char*ch,int&i);

//从ch数组中读取字符串,构造表达式

voidCreateExp(ExpTree&E,char*ch,int&i);

//StatusInputCreateExp(ExpTree&E);

//从键盘先序输入来构造表达式树T

StatusVisit(ExpTreee);

//输出e的内容

voidInorderExp(ExpTreeE,Status(*Visit)(ExpTreee));

//输出中序表达式用带括号的中缀表示式输出

StatusAssign(ExpTreeE,charv,floatc);

//对表达式内的所有v,赋值c

floatValue(ExpTreeE);

//计算表达式的值

ExpTreeCompound(charp,ExpTreee1,ExpTreee2);

//5.构造一个新的复合表达式(E1)P(E2)

StatusDiff(ExpTree&E,charV);

//求表达式E对变量V的导数

voidMergeConst(ExpTreeE);

//合并表达式种所有常数运算

StatusPreOrderTraverse(ExpTreeE,Status(*Visit)(ExpTreee));

//波兰式输出

StatusPostOrderTraverse(ExpTreeE,Status(*Visit)(ExpTreee));

//逆波兰式输出

2、队列。

typedefcharQElemType;

typedefstructQNode

{

QElemTypedata;

structQNode*next;

}QNode,*QuePtr;

typedefstruct

{

QuePtrfront;

QuePtrrear;

}Queue;

基本操作:

StatusInitQueue(Queue&Q);

//构造一个空队列

StatusDestroyQueue(Queue&Q);

//销毁队列

StatusQueueEmpty(QueueQ);

//判空

StatusEnQueue(Queue&Q,QElemTypee);

//插入元素e为Q的新的队尾元素

StatusDeQueue(Queue&Q,QElemType&e);

//删除队头元素,用e返回其值,并返回OK,否则返回ERROR;

 

3、栈

typedefstruct

{

SElemType*base;

SElemType*top;

intstacksize;

}SqStack;

基本操作:

StatusInitStack(SqStack&S);

StatusStackEmpty(SqStackS);

StatusPush(SqStack&S,SElemTypee);

StatusPop(SqStack&S,SElemType&e);

SElemTypeTop(SqStackS);

 

4、主函数和其他主要函数

1)、访问函数(输出函数)

StatusVisit(ExpTreee)

//输出e的内容

{

intm,n[5];

if(e->tag==OPER)//运算符

printf("%s",e->expr);

elseif(e->tag==VAR)//变量

{

if(!

e->vary.val)//变量的值是0

printf("%c",e->vary.var);//输出变量名

else

printf("%0.4f",e->vary.val);//输出变量的值

}

else//常量

{

if(e->ordina>=0)//正数

printf("%d",e->ordina);

else

printf("(%d)",e->ordina);//负数,输出时加括号

}

returnOK;

}

2)、构造表达式

StatusArrayCreateExp(ExpTree&E,char*ch,int&i)

//从ch数组中读取字符串,构造表达式

{

if(ch[i])

{

if(!

(E=(ExpTree)malloc(sizeof(ExpNode))))

returnERROR;

if(ch[i]=='s'&&ch[i+1]=='i'&&ch[i+2]=='n'||//sin

ch[i]=='S'&&ch[i+1]=='I'&&ch[i+2]=='N'||

ch[i]=='c'&&ch[i+1]=='o'&&ch[i+2]=='s'||//cos

ch[i]=='C'&&ch[i+1]=='O'&&ch[i+2]=='S'||

ch[i]=='t'&&ch[i+1]=='a'&&ch[i+2]=='n'||//tan

ch[i]=='T'&&ch[i+1]=='A'&&ch[i+2]=='N')

{

E->tag=OPER;

E->expr[0]=ch[i];E->expr[1]=ch[++i];E->expr[2]=ch[++i];

E->expr[3]='\0';

ArrayCreateExp(E->rchild,ch,++i);//只建右子树

E->lchild=NULL;//左子树为空

returnOK;

}

elseif(ch[i]>='0'&&ch[i]<='9')//数字

{

E->tag=ORD;

E->ordina=ch[i]-'0';

}

elseif(ch[i]>='a'&&ch[i]<='z')//变量

{

E->tag=VAR;

E->vary.var=ch[i];

E->vary.val=0;

}

elseif(ch[i]=='+'||ch[i]=='-'||ch[i]=='*'||ch[i]=='/'||ch[i]=='^')//运算符

{

E->tag=OPER;

E->expr[0]=ch[i];

E->expr[1]='\0';

}

if(!

E->tag)//E是运算符

{

ArrayCreateExp(E->lchild,ch,++i);

ArrayCreateExp(E->rchild,ch,++i);

}

else

{

E->lchild=NULL;

E->rchild=NULL;

}

}

returnOK;

}

3)、带括号的中缀表示式输出

voidInorderExp(ExpTreeE,Status(*Visit)(ExpTreee))

//输出中序表达式用带括号的中缀表示式输出

{

intbracket;

if(E)

{

if(E->lchild)

{

bracket=precede(E,E->lchild);//比较双亲与左孩子运算符优先级

if(bracket>0)//左孩子优先级低

printf("(");

InorderExp(E->lchild,Visit);

if(bracket>0)

printf(")");

}

Visit(E);

if(E->rchild)

{

bracket=precede(E,E->rchild);//比较双亲与右孩子运算符优先级

if(bracket>=0)//右孩子优先级低

printf("(");

InorderExp(E->rchild,Visit);

if(bracket>=0)

printf(")");

}

}

}

 

4)、计算表达式的值

floatValue(ExpTreeE)

//计算表达式的值

{

floatlv,rv,value=0;

if(E)

{

if(E->tag==VAR)//是变量

return(E->vary.val);

if(E->tag==ORD)

return(E->ordina);

if(E->lchild)lv=Value(E->lchild);

rv=Value(E->rchild);

switch(E->expr[0])

{

case'+':

value=lv+rv;break;

case'-':

value=lv-rv;break;

case'*':

value=lv*rv;break;

case'/':

if(rv)value=lv/rv;

elseexit(0);

break;

case'^':

value=power(lv,rv);break;

case'S':

case's':

value=sin(rv);break;//sin

case'T':

case't':

value=tan(rv);break;//tan

case'C':

case'c':

if(E->expr[2]=='S'||E->expr[2]=='s')//cos

{value=cos(rv);

break;

}

}

}

return(value);

}

5)、合并常数

voidMergeConst(ExpTreeE)

//合并表达式中所有常数运算

{

if(!

E->lchild&&!

E->rchild)return;//叶子

if(E->tag==OPER&&E->lchild&&E->rchild&&E->lchild->tag==ORD&&E->rchild->tag==ORD)

{

E->tag=ORD;

switch(E->expr[0])

{

case'*':

E->ordina=E->lchild->ordina*E->rchild->ordina;break;

case'/':

E->ordina=E->lchild->ordina/E->rchild->ordina;break;

case'^':

E->ordina=power(E->lchild->ordina,E->rchild->ordina);break;

case'+':

E->ordina=E->lchild->ordina+E->rchild->ordina;break;

case'-':

E->ordina=E->lchild->ordina-E->rchild->ordina;break;

}

free(E->lchild);

free(E->rchild);

E->lchild=NULL;

E->rchild=NULL;

}

else

{

if(E->lchild)

MergeConst(E->lchild);

if(E->rchild)

MergeConst(E->rchild);

}

}

5、构造的表达式如图

算术表达式前缀表示:

*+ab-cd

中缀带括号表示:

(a+b)*(c-d)

四、调试分析

1、调试过程中遇到了许多问题,下面举几个例子。

(1)赋值出错处理

在调试赋值函数时发生了“赋值失败的情况”

修改前的函数:

voidFindVary(char*c,char*e)

//找出表达式中的变量

{

inti=-1,j=0;

while(e[++i])

if(e[i]>='A'&&e[i]<='Z'||e[i]>='a'&&e[i]<='z'){

i+=2;

continue;}

else

c[j++]=e[i];

c[j]=0;

}

调试出现下面的情况

 

出现了两次了对X的赋值,原因是我在编写voidFindVary(char*c,ch

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1