目录
一、系统开发的背景 1
二、系统分析与设计 1
(一) 系统功能要求 1
(二) 系统模块结构设计 1
三、系统的设计与实现 3
(一) 二叉树的遍历 3
(二) 算术表达式求值 5
四、系统测试 9
(一) 测试二叉树遍历函数 9
(二) 测试算术表达式求值函数 10
五、总结 10
六、附件(代码、部分图表) 10
(一) 程序代码 10
(二) 实验截图 15
算术表达式与二叉树
一、系统开发的背景
为了方便进行基本的算术运算,减轻对数字较大的数操作时所带来的麻烦,及其在运算过程中错误的避免。因此设计算术表达式与二叉树的程序来解决此问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
。
二、系统分析与设计
(一) 系统功能要求
由于一个表达式和一棵二叉树之间,存在着自然的对应关系。遍写一个程序,实现基于二叉树表示的算术表达式的操作。算术表达式内可以含有变量(a~z)、常量(0~9)和二元运算符(+,-,*,/,^(乘幂))。
具体实现以下操作:
1以字符序列的形式输入语法正确的前缀表达式并构造表达式。
2用带括弧的中缀表达式输出表达式。
3实现对变量V的赋值(V=c),变量的初值为0。
4对算术表达式E求值。
(二) 系统模块结构设计
通过对系统功能的分析,基于二叉树表示的算术表达式的功能
如图(1)所示。
图1:基于二叉树表示的算术表达式的功能图
通过上图的功能分析,把整个系统划分为主要的两大个模块:
1、 将语法正确的前缀表达式用二叉树的遍历转换成相应的遍历序列,必要时可以求出此二叉树的结点数及其树的深度。该模块借助函数BiTree Create(BiTree T)创建二叉树,void Preorder(BiTree T) 先序遍历, void InOrder(BiTree T) 中序遍历,void PostOrder(BiTree T) 后序遍历,int Sumleaf(BiTree T) 统计叶结点的数目,int Depth(BiTree T) 二叉树的深度6个函数联合来实现;
2、 计算中序遍历所得的算术表达式的值。其中先要将扫描得到的中缀表达式转换为后缀表达式,然后利用栈的初始化,进栈与取栈顶元素操作进行对后缀表达式进行计算。该模块借助函数void InitStack(SeqStack *S)初始化栈,int PushStack(SeqStack *S,char e)进栈,int GetTop(SeqStack S,char *e)取栈顶元素,void TranslateExpress(char str[],char exp[])中缀表达式转后缀表达式,float ComputeExpress(char a[])计算后缀表达式的值来实现;
三、系统的设计与实现
(一) 二叉树的遍历
分析:首先构建一棵二叉树,然后依次输出每个遍历的序列。流程图如图2所示。
图2:二叉树的遍历流程图
该模块的具体代码如下所示:
#include
#include
#define MaxSize 50
typedef struct
{ float data[MaxSize];
int top;
}OpStack;
typedef struct
{char data[MaxSize];
int top;
}SeqStack;
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree Create(BiTree T)//用扩展先序遍历序列创建二叉树
{ char ch;
ch=getchar();
if(ch=='0')
T=NULL;
else {
T=new BiTNode;
T->data=ch;
T->lchild=Create(T->lchild);
T->rchild=Create(T->rchild); }
return T;}
void Visit(char ch)//访问根节点
{ printf("%c ",ch);}
void Preorder(BiTree T)//先序遍历
{ if(T==NULL)
return;
Visit(T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
void InOrder(BiTree T)//中序遍历
{ if(T==NULL)
return;
InOrder(T->lchild);
Visit(T->data);
InOrder(T->rchild);
}
void PostOrder(BiTree T)//后序遍历
{if(T==NULL)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
Visit(T->data);
}
int Sumleaf(BiTree T)//统计叶结点的数目
{int sum=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;}
return sum;
}
int Depth(BiTree T)//二叉树的深度
{int dep=0,depl,depr;
if(!T) dep=0;
else{
depl=Depth(T->lchild);
depr=Depth(T->rchild);
dep=1+(depl>depr?depl:depr);}
return dep;
}
void main()
{
BiTree T;
int sum,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
#define NULL 0
#define MaxSize 50
typedef struct
{ float data[MaxSize];
int top;
}OpStack;
typedef struct
{char data[MaxSize];
int top;
}SeqStack;
void InitStack(SeqStack *S)//初始化栈
{ S->top=0; }
int StackEmpty(SeqStack S)//判断栈是否为空
{ if(S.top ==0) return 1;
else return 0; }
int PushStack(SeqStack *S,char e)//进栈
{if(S->top>=MaxSize)
{ printf("栈已满,不能进栈!");
return 0;
} else
{ S->data[S->top]=e;
S->top++;
return 1; } }
int PopStack(SeqStack *S,char *e)//删除栈顶元素
{ if(S->top==0)
{ printf("栈已空\n");
return 0;
} else {S->top--;
*e=S->data[S->top];
return 1; } }
int GetTop(SeqStack S,char *e)//取栈顶元素
{ if(S.top<=0)
{printf("栈已空"); return 0;
}else {*e=S.data[S.top-1];
return 1; } }
void TranslateExpress(char str[],char exp[])//把中缀表达式转换为后缀表达式
{SeqStack S; char ch; char e;
int i=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'; }
float ComputeExpress(char a[])//计算后缀表达式的值
{OpStack S;
int i=0; float x1,x2,value; float result;
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)
return result;
else { printf("表达式错误");
exit(-1); }
} return 0; }
void main()
{char a[MaxSize],b[MaxSize];
float f;
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//tandard library标准库函数头文件,stdlib.h里面定义了五种类型、 一些宏和通用工具函数
#include//数学库函数
#define NULL 0
#define MaxSize 50
typedef struct
{ float data[MaxSize];
int top;
}OpStack;//存放数字的栈
typedef struct
{char data[MaxSize];
int top;
}SeqStack;//存放运算符的栈
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree Create(BiTree T)//用扩展先序遍历序列创建二叉树
{ char ch;
ch=getchar();
if(ch=='0')
T=NULL;
else { T=new BiTNode;
T->data=ch;
T->lchild=Create(T->lchild);
T->rchild=Create(T->rchild); }
return T;}
void Visit(char ch)//访问根节点
{ printf("%c ",ch);}
void Preorder(BiTree T)//先序遍历
{ if(T==NULL)
return;
Visit(T->data);
Preorder(T->lchild);
Preorder(T->rchild);}
void InOrder(BiTree T)//中序遍历
{ if(T==NULL)
return;
InOrder(T->lchild);
Visit(T->data);
InOrder(T->rchild);}
void PostOrder(BiTree T)//后序遍历
{ if(T==NULL)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
Visit(T->data); }
int Sumleaf(BiTree T)//统计叶结点的数目
{int sum=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;}
return sum;}
int Depth(BiTree T)//二叉树的深度
{int dep=0,depl,depr;
if(!T) dep=0;
else{
depl=Depth(T->lchild);
depr=Depth(T->rchild);
dep=1+(depl>depr?depl:depr);}
return dep;}
void InitStack(SeqStack *S)//初始化栈
{ S->top=0; }
int StackEmpty(SeqStack S)//判断栈是否为空
{ if(S.top ==0) return 1;
else return 0; }
int PushStack(SeqStack *S,char e)//进栈
{if(S->top>=MaxSize)
{ printf("栈已满,不能进栈!");
return 0; }
else { S->data[S->top]=e;
S->top++;
return 1; } }
int PopStack(SeqStack *S,char *e)//删除栈顶元素
{ if(S->top==0) { printf("栈已空\n");
return 0; } else
{S->top--; *e=S->data[S->top];
return 1; } }
int GetTop(SeqStack S,char *e)//取栈顶元素
{ if(S.top<=0) {printf("栈已空");
return 0; } else {*e=S.data[S.top-1];
return 1; } }
void TranslateExpress(char str[],char exp[])//把中缀表达式转换为后缀表达式
{SeqStack S; char ch; char e; int i=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';
}
float ComputeExpress(char a[])//计算后缀表达式的值
{OpStack S; int i=0; float x1,x2,value; float result; 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,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) return result;
else { printf("表达式错误");
exit(-1); } }
return 0; }
void main()
{BiTree T;int sum,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);
char a[MaxSize],b[MaxSize]; float f;
printf("请输入一个算术表达式:");
scanf("%s",&a);
printf("中缀表达式为:%s\n",a);
TranslateExpress(a,b);
printf("后缀表达式为:%s\n",b);
f=ComputeExpress(b);
printf("计算结果:%f\n",f); }
(二) 实验截图:
图7-a:基于二叉树的算术表达式
图7-b:基于二叉树的算术表达式