算术表达式与二叉树.docx
《算术表达式与二叉树.docx》由会员分享,可在线阅读,更多相关《算术表达式与二叉树.docx(21页珍藏版)》请在冰豆网上搜索。
算术表达式与二叉树
算术表达式与二叉树
一、系统开发的背景
为了方便进行基本的算术运算,减轻对数字较大的数操作时所带来的麻烦,及其在运算过程中错误的避免。
因此设计算术表达式与二叉树的程序来解决此问题。
二、系统分析与设计
(一)系统功能要求
由于一个表达式和一棵二叉树之间,存在着自然的对应关系。
遍写一个程序,实现基于二叉树表示的算术表达式的操作。
算术表达式内可以含有变量(a~z)、常量(0~9)和二元运算符(+,-,*,/,^(乘幂))。
具体实现以下操作:
1以字符序列的形式输入语法正确的前缀表达式并构造表达式。
2用带括弧的中缀表达式输出表达式。
3实现对变量V的赋值(V=c),变量的初值为0。
4对算术表达式E求值。
(二)系统模块结构设计
通过对系统功能的分析,基于二叉树表示的算术表达式的功能
如图
(1)所示。
图1:
基于二叉树表示的算术表达式的功能图
通过上图的功能分析,把整个系统划分为主要的两大个模块:
1、将语法正确的前缀表达式用二叉树的遍历转换成相应的遍历序列,必要时可以求出此二叉树的结点数及其树的深度。
该模块借助函数BiTreeCreate(BiTreeT)创建二叉树,voidPreorder(BiTreeT)先序遍历,voidInOrder(BiTreeT)中序遍历,voidPostOrder(BiTreeT)后序遍历,intSumleaf(BiTreeT)统计叶结点的数目,intDepth(BiTreeT)二叉树的深度6个函数联合来实现;
2、计算中序遍历所得的算术表达式的值。
其中先要将扫描得到的中缀表达式转换为后缀表达式,然后利用栈的初始化,进栈与取栈顶元素操作进行对后缀表达式进行计算。
该模块借助函数voidInitStack(SeqStack*S)初始化栈,intPushStack(SeqStack*S,chare)进栈,intGetTop(SeqStackS,char*e)取栈顶元素,voidTranslateExpress(charstr[],charexp[])中缀表达式转后缀表达式,floatComputeExpress(chara[])计算后缀表达式的值来实现;
三、系统的设计与实现
(一)二叉树的遍历
分析:
首先构建一棵二叉树,然后依次输出每个遍历的序列。
流程图如图2所示。
图2:
二叉树的遍历流程图
该模块的具体代码如下所示:
#include
#include
#defineMaxSize50
typedefstruct
{floatdata[MaxSize];
inttop;
}OpStack;
typedefstruct
{chardata[MaxSize];
inttop;
}SeqStack;
typedefstructBiTNode{
chardata;
structBiTNode*lchild,*rchild;
}BiTNode,*BiTree;
BiTreeCreate(BiTreeT)//用扩展先序遍历序列创建二叉树
{charch;
ch=getchar();
if(ch=='0')
T=NULL;
else{
T=newBiTNode;
T->data=ch;
T->lchild=Create(T->lchild);
T->rchild=Create(T->rchild);}
returnT;}
voidVisit(charch)//访问根节点
{printf("%c",ch);}
voidPreorder(BiTreeT)//先序遍历
{if(T==NULL)
return;
Visit(T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
voidInOrder(BiTreeT)//中序遍历
{if(T==NULL)
return;
InOrder(T->lchild);
Visit(T->data);
InOrder(T->rchild);
}
voidPostOrder(BiTreeT)//后序遍历
{if(T==NULL)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
Visit(T->data);
}
intSumleaf(BiTreeT)//统计叶结点的数目
{intsum=0,m,n;
if(T)
{if((!
T->lchild)&&(!
T->rchild))//该结点的左或右分支为空时
sum++;
m=Sumleaf(T->lchild);
sum=sum+m;
n=Sumleaf(T->rchild);
sum=sum+n;}
returnsum;
}
intDepth(BiTreeT)//二叉树的深度
{intdep=0,depl,depr;
if(!
T)dep=0;
else{
depl=Depth(T->lchild);
depr=Depth(T->rchild);
dep=1+(depl>depr?
depl:
depr);}
returndep;
}
voidmain()
{
BiTreeT;
intsum,k;
printf("请输入二叉树中的元素(以扩展先序遍历序列输入):
\n");
T=Create(T);
printf("先序遍历序列为:
");
Preorder(T);
printf("\n");
printf("中序遍历序列为:
");
InOrder(T);
printf("\n");
printf("后序遍历序列为:
");
PostOrder(T);
printf("\n");
sum=Sumleaf(T);
printf("叶结点的数目为:
%d\n",sum);
k=Depth(T);
printf("二叉树的深度为:
%d\n",k);
}
(二)算术表达式求值
分析:
首先初始化一个栈,然后对相关的数据元素及运算符进栈,之后中缀表达式转后缀表达式计算出后缀表达式的值。
流程图如图3所示。
图3:
算术表达式求值流程图
该模块的具体代码如下所示:
#include
#include
#include
#include
#include
#defineNULL0
#defineMaxSize50
typedefstruct
{floatdata[MaxSize];
inttop;
}OpStack;
typedefstruct
{chardata[MaxSize];
inttop;
}SeqStack;
voidInitStack(SeqStack*S)//初始化栈
{S->top=0;}
intStackEmpty(SeqStackS)//判断栈是否为空
{if(S.top==0)return1;
elsereturn0;}
intPushStack(SeqStack*S,chare)//进栈
{if(S->top>=MaxSize)
{printf("栈已满,不能进栈!
");
return0;
}else
{S->data[S->top]=e;
S->top++;
return1;}}
intPopStack(SeqStack*S,char*e)//删除栈顶元素
{if(S->top==0)
{printf("栈已空\n");
return0;
}else{S->top--;
*e=S->data[S->top];
return1;}}
intGetTop(SeqStackS,char*e)//取栈顶元素
{if(S.top<=0)
{printf("栈已空");return0;
}else{*e=S.data[S.top-1];
return1;}}
voidTranslateExpress(charstr[],charexp[])//把中缀表达式转换为后缀表达式
{SeqStackS;charch;chare;
inti=0,j=0;
InitStack(&S);
ch=str[i];i++;
while(ch!
='\0')//依次扫描中缀表达式
{switch(ch)
{case'(':
PushStack(&S,ch);break;
case')':
while(GetTop(S,&e)&&e!
='(')
{PopStack(&S,&e);
exp[j]=e;
j++;}
PopStack(&S,&e);break;
case'+':
case'-':
while(!
StackEmpty(S)&&GetTop(S,&e)&&e!
='(')
{PopStack(&S,&e);
exp[j]=e;
j++;}
PushStack(&S,ch);break;
case'^':
case'*':
case'/':
while(!
StackEmpty(S)&&GetTop(S,&e)&&e=='/'||e=='*'||e=='^')
{PopStack(&S,&e);
exp[j]=e;j++;}
PushStack(&S,ch);
break;//是空格就忽略
case'':
break;
default:
while(ch>='0'&&ch<='9')
{exp[j]=ch;j++;
ch=str[i];
i++;}
i--;exp[j]='';
j++;}
ch=str[i];
i++;}
while(!
StackEmpty(S))//将栈中剩余运算符出栈
{PopStack(&S,&e);
exp[j]=e;
j++;}exp[j]='\0';}
floatComputeExpress(chara[])//计算后缀表达式的值
{OpStackS;
inti=0;floatx1,x2,value;floatresult;
S.top=-1;
while(a[i]!
='\0')//依次扫描后缀表达式
{if(a[i]!
=''&&a[i]>='0'&&a[i]<='9')//如果是数字
{value=0;
while(a[i]!
='')//如果不是空格
{value=10*value+a[i]-'0';
i++;
}S.top++;
S.data[S.top]=value;//处理后进栈
}else//如果是运算符
{switch(a[i])
{case'+':
x1=S.data[S.top];S.top--;
x2=S.data[S.top];S.top--;
result=x1+x2;S.top++;
S.data[S.top]=result;break;
case'-':
x1=S.data[S.top];S.top--;
x2=S.data[S.top];S.top--;
result=x2-x1;S.top++;
S.data[S.top]=result;break;
case'*':
x1=S.data[S.top];S.top--;
x2=S.data[S.top];S.top--;
result=x1*x2;S.top++;
S.data[S.top]=result;break;
case'/':
x1=S.data[S.top];S.top--;
x2=S.data[S.top];S.top--;
result=x2/x1;S.top++;
S.data[S.top]=result;break;
case'^':
x1=S.data[S.top];S.top--;
x2=S.data[S.top];S.top--;
result=float(pow(x1,x2));S.top++;
S.data[S.top]=result;break;
}i++;
}}
if(S.top!
=-1)//如果栈不空,将结果出栈并返回
{result=S.data[S.top];
S.top--;if(S.top==-1)
returnresult;
else{printf("表达式错误");
exit(-1);}
}return0;}
voidmain()
{chara[MaxSize],b[MaxSize];
floatf;
printf("请输入一个算术表达式:
");
scanf("%s",&a);
printf("中缀表达式为:
%s\n",a);
TranslateExpress(a,b);
printf("后缀表达式为:
%s\n",b);
f=ComputeExpress(b);
printf("计算结果:
%f\n",f);}
四、系统测试
(一)测试二叉树遍历函数:
测试的结果如图4。
图4:
二叉树的遍历
(二)测试算术表达式求值函数:
测试的结果如图5,6。
图5
图6
五、总结
系统完成了对基本的数学算术运算的求值的功能。
系统不能对更高一级的复合表达式(如三角函数等)求值,是其不足之处。
我的收获是经过不断的查询相关的书籍与有关的资料,使得我对原本不熟的知识有了深刻的了解和认识。
也让我能够更加独立的去学习,提高了我的自主学习的能力。
六、附件(代码、部分图表)
(一)程序代码:
#include
#include//字符串函数
#include//功能:
分配字节的存储区,若内存不够返回0.
#include//tandardlibrary标准库函数头文件,stdlib.h里面定义了五种类型、一些宏和通用工具函数
#include//数学库函数
#defineNULL0
#defineMaxSize50
typedefstruct
{floatdata[MaxSize];
inttop;
}OpStack;//存放数字的栈
typedefstruct
{chardata[MaxSize];
inttop;
}SeqStack;//存放运算符的栈
typedefstructBiTNode{
chardata;
structBiTNode*lchild,*rchild;
}BiTNode,*BiTree;
BiTreeCreate(BiTreeT)//用扩展先序遍历序列创建二叉树
{charch;
ch=getchar();
if(ch=='0')
T=NULL;
else{T=newBiTNode;
T->data=ch;
T->lchild=Create(T->lchild);
T->rchild=Create(T->rchild);}
returnT;}
voidVisit(charch)//访问根节点
{printf("%c",ch);}
voidPreorder(BiTreeT)//先序遍历
{if(T==NULL)
return;
Visit(T->data);
Preorder(T->lchild);
Preorder(T->rchild);}
voidInOrder(BiTreeT)//中序遍历
{if(T==NULL)
return;
InOrder(T->lchild);
Visit(T->data);
InOrder(T->rchild);}
voidPostOrder(BiTreeT)//后序遍历
{if(T==NULL)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
Visit(T->data);}
intSumleaf(BiTreeT)//统计叶结点的数目
{intsum=0,m,n;
if(T){
if((!
T->lchild)&&(!
T->rchild))//该结点的左或右分支为空时
sum++;m=Sumleaf(T->lchild);
sum=sum+m;n=Sumleaf(T->rchild);
sum=sum+n;}
returnsum;}
intDepth(BiTreeT)//二叉树的深度
{intdep=0,depl,depr;
if(!
T)dep=0;
else{
depl=Depth(T->lchild);
depr=Depth(T->rchild);
dep=1+(depl>depr?
depl:
depr);}
returndep;}
voidInitStack(SeqStack*S)//初始化栈
{S->top=0;}
intStackEmpty(SeqStackS)//判断栈是否为空
{if(S.top==0)return1;
elsereturn0;}
intPushStack(SeqStack*S,chare)//进栈
{if(S->top>=MaxSize)
{printf("栈已满,不能进栈!
");
return0;}
else{S->data[S->top]=e;
S->top++;
return1;}}
intPopStack(SeqStack*S,char*e)//删除栈顶元素
{if(S->top==0){printf("栈已空\n");
return0;}else
{S->top--;*e=S->data[S->top];
return1;}}
intGetTop(SeqStackS,char*e)//取栈顶元素
{if(S.top<=0){printf("栈已空");
return0;}else{*e=S.data[S.top-1];
return1;}}
voidTranslateExpress(charstr[],charexp[])//把中缀表达式转换为后缀表达式
{SeqStackS;charch;chare;inti=0,j=0;InitStack(&S);
ch=str[i];i++;
while(ch!
='\0')//依次扫描中缀表达式
{switch(ch)
{case'(':
PushStack(&S,ch);break;
case')':
while(GetTop(S,&e)&&e!
='(')
{PopStack(&S,&e);
exp[j]=e;j++;}
PopStack(&S,&e);break;
case'+':
case'-':
while(!
StackEmpty(S)&&GetTop(S,&e)&&e!
='(')
{PopStack(&S,&e);
exp[j]=e;
j++;}
PushStack(&S,ch);break;
case'^':
case'*':
case'/':
while(!
StackEmpty(S)&&GetTop(S,&e)&&e=='/'||e=='*'||e=='^')
{PopStack(&S,&e);
exp[j]=e;
j++;}
PushStack(&S,ch);
break;//是空格就忽略
case'':
break;
default:
while(ch>='0'&&ch<='9')
{exp[j]=ch;j++;ch=str[i];
i++;}i--;
exp[j]='';
j++;}ch=str[i];
i++;}
while(!
StackEmpty(S))//将栈中剩余运算符出栈
{PopStack(&S,&e);
exp[j]=e;j++;}
exp[j]='\0';
}
floatComputeExpress(chara[])//计算后缀表达式的值
{OpStackS;inti=0;floatx1,x2,value;floatresult;S.top=-1;
while(a[i]!
='\0')//依次扫描后缀表达式
{if(a[i]!
=''&&a[i]>='0'&&a[i]<='9')//如果是数字
{value=0;while(a[i]!
='')//如果不是空格
{value=10*value+a[i]-'0';i++;}//相当于一个循环,把数组a[]值赋给value.
S.top++;
S.data[S.top]=value;//处理后进栈
}else//如果是运算符
{switch(a[i])
{case'+':
x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;
result=x1+x2;S.top++;
S.data[S.top]=result;break;
case'-':
x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;
result=x2-x1;S.top++;
S.data[S.top]=result;break;
case'*':
x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;
result=x1*x2;
S.top++;
S.data[S.top]=result;break;
case'/':
x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;
result=x2/x1;S.top++;
S.data[S.top]=result;break;
case'^':
x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;
result=float(pow(x1