数据结构二叉树运算器实验报告.docx
- 文档编号:8306716
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:21
- 大小:20.85KB
数据结构二叉树运算器实验报告.docx
《数据结构二叉树运算器实验报告.docx》由会员分享,可在线阅读,更多相关《数据结构二叉树运算器实验报告.docx(21页珍藏版)》请在冰豆网上搜索。
数据结构二叉树运算器实验报告
二叉树运算器
一、问题描述
本实验主要实现对二叉树的多种方式创建、多种方式遍历、复制、销毁,求二叉树的结点数、叶子数、高度、宽度、每层宽度,用二叉树对中缀式还原,用二叉树进行求值。
二、存储结构
typedefstructBiTNode{
TElemTypedata;
structBiTNode*lchild,*rchild;
}BiNode,*BiTree;
二叉树每个结点包括数据及指向左右孩子的指针。
三、算法思想
对指针、栈、队列的综合应用。
四、程序结构
#include
#include
#include
#defineSTACK_INIT_SIZE100
#defineSTACKINCREASE10
typedefcharTElemType;
typedefstructBiTNode{
TElemTypedata;
structBiTNode*lchild,*rchild;
}BiNode,*BiTree;
typedefBiTreeSElemType;
typedefBiTreeQElemType;
typedefstructQNode{
QElemTypedata;
structQNode*next;
}QNode,*Queue;
typedefstruct{
Queuefront;
Queuerear;
}LinkQueue;
typedefstruct{
SElemType*base;
SElemType*top;
intstacksize;
}SqStack;
/*====================栈-ADT====================*/
voidInitStack(SqStack&S){
S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
}//InitStack
voidPush(SqStack&S,SElemTypee){
if(S.top-S.base>=S.stacksize){
S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREASE)*sizeof(SElemType));
if(!
S.base)
exit
(1);
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREASE;
}
*S.top++=e;
}
intPop(SqStack&S,SElemType&e){
if(S.base==S.top)
return-1;
e=*--S.top;
return0;
}
/*====================队列-ADT====================*/
voidInitQueue(LinkQueue&Q){
Q.front=Q.rear=(Queue)malloc(sizeof(QNode));
if(!
Q.front)exit
(1);
Q.front->next=NULL;
}//InitQueue
voidEnQueue(LinkQueue&Q,QElemTypee){
Queuep;
p=(Queue)malloc(sizeof(QNode));
if(!
p)exit
(1);
p->data=e;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
Q.rear->next=NULL;
}//EnQueue
intDeQueue(LinkQueue&Q,QElemType&e){
Queuep;
if(Q.front==Q.rear)
return0;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p){
Q.rear=Q.front;
Q.rear->next=NULL;
}
free(p);
return0;
}//DeQueue
/*====================二叉树-ADT====================*/
BiTreePreCreateBiTree(){
BiTreep;
charch;
ch=getchar();
ch=getchar();
if(ch=='#')returnNULL;
p=(BiTree)malloc(sizeof(BiNode));
p->data=ch;
p->lchild=PreCreateBiTree();
p->rchild=PreCreateBiTree();
returnp;
}//PreCreateBiTree
这是先序扩展序列创建二叉树,主要是递归调用,先赋值给双亲,再进行调用。
voidPostCreateBiTree1(BiTree&bt){
SqStackS;
charch;
BiTreep;
InitStack(S);
while
(1){
ch=getchar();
ch=getchar();
if(ch=='@')
break;
if(ch=='#')
Push(S,NULL);
else{
p=(BiTree)malloc(sizeof(BiNode));
p->data=ch;
Pop(S,p->rchild);
Pop(S,p->lchild);
Push(S,p);
}
}
Pop(S,bt);
}//PostCreateBiTree1
这是后序扩展序列创建二叉树,序列从左向右输入,以@为结束符。
扫描入栈时,每当遇到字符,则弹出两个栈顶指针最为右孩子和左孩子,直至遇到结束符@。
BiTreePostCreateBiTree2(){
charch;
BiTreep;
ch=getchar();
ch=getchar();
if(ch=='#')
returnNULL;
p=(BiTree)malloc(sizeof(BiNode));
p->data=ch;
p->rchild=PostCreateBiTree2();
p->lchild=PostCreateBiTree2();
returnp;
}//PostCreateBiTree2
这也是后序扩展序列创建二叉树,不过是从右向左输入,扫描时,每当遇到#则返回空指针。
还是用递归,先创建右孩子,再创建左孩子。
intPre_InCreate(BiTree&bt,char*P,char*Q,intn){
inti;
bt=(BiTree)malloc(sizeof(BiNode));
bt->data=P[0];
if(n==1){
bt->lchild=NULL;
bt->rchild=NULL;
return0;
}
for(i=0;i if(Q[i]==P[0]) break; } if(i! =0){ bt->lchild=(BiTree)malloc(sizeof(BiNode)); bt->lchild->data=P[1]; Pre_InCreate(bt->lchild,P+1,Q,i); } else bt->lchild=NULL; if(i! =n-1){ bt->rchild=(BiTree)malloc(sizeof(BiNode)); bt->rchild->data=P[1+i]; Pre_InCreate(bt->rchild,P+1+i,Q+1+i,n-1-i); } else bt->rchild=NULL; return0; }//Pre_InCreate 这是用先序和中序序列创建二叉树。 主要通过分析两个序列之间的关系,通过两个序列的头尾指针和结点数,先找到双亲,再找到左右孩子,然后递归调用向下创建。 主要注意结点数的变化。 intIn_PostCreate(BiTree&bt,char*P,char*Q,intn){ inti; bt=(BiTree)malloc(sizeof(BiNode)); bt->data=Q[n-1]; if(n==1){ bt->lchild=NULL; bt->rchild=NULL; return0; } for(i=0;i if(P[i]==Q[n-1]) break; } if(i! =0){ bt->lchild=(BiTree)malloc(sizeof(BiNode)); bt->lchild->data=Q[i-1]; In_PostCreate(bt->lchild,P,Q,i); } else bt->lchild=NULL; if(i! =n-1){ bt->rchild=(BiTree)malloc(sizeof(BiNode)); bt->rchild->data=Q[n-2]; In_PostCreate(bt->rchild,P+i+1,Q+i,n-i-1); } else bt->rchild=NULL; return0; }//In_PostCreate 这是中序和后序序列创建二叉树。 与先序和中序一样,不再多说。 不过用先序和后序应该不能创建,因为会产生多种可能。 voidVisit(TElemTypech){ printf("%c",ch); }//Visit 用来打印data。 intPreRead(BiTreebt){ if(! bt) return0; Visit(bt->data); PreRead(bt->lchild); PreRead(bt->rchild); return0; }//PreRead 先序遍历,先将data打印,再递归调用。 intInRead(BiTreebt){ if(! bt) return0; InRead(bt->lchild); Visit(bt->data); InRead(bt->rchild); return0; }//InRead 中序遍历,先递归调用左孩子,再打印data,再调用右孩子。 intPostRead(BiTreebt){ if(! bt) return0; PostRead(bt->lchild); PostRead(bt->rchild); Visit(bt->data); return0; }//PostRead 后序遍历,先将左右孩子递归调用,再打印data。 intTierRead(BiTreebt){ LinkQueueQ; BiTreep; if(! bt) return0; InitQueue(Q); EnQueue(Q,bt); while(! (Q.front==Q.rear)){ DeQueue(Q,p); Visit(p->data); if(p->lchild)EnQueue(Q,p->lchild); if(p->rchild)EnQueue(Q,p->rchild); } return0; }//TierRead 按层遍历,运用队列,先将头指针入队,然后首队结点出队打印,每打印一个,其左右孩子入队。 直至队列为空。 intNumber(BiTreebt){ intn1,n2; if(! bt)return0; n1=Number(bt->lchild); n2=Number(bt->rchild); return1+n1+n2; }//Number 求二叉树结点数,递归调用,当头指针为空时,返回0,否则返回1+左孩子结点数+右孩子结点数。 intLeaf(BiTreebt){ intl1,l2; if(! bt)return0; if(! bt->lchild&&! bt->rchild)return1; l1=Leaf(bt->lchild); l2=Leaf(bt->rchild); returnl1+l2; }//Leaf 求二叉树叶子数,递归调用,若头指针为空时,返回0,若头指针左右孩子为空,则返回1,否则返回左孩子叶子数+右孩子叶子数。 intHeight(BiTreebt){ inth1,h2; if(! bt)return0; h1=Height(bt->lchild); h2=Height(bt->rchild); return1+(h1>h2? h1: h2); }//Height 求二叉树的高度,递归调用,当头指针为空时,返回0,否则返回1+(左右孩子中高度最大的)。 intWide(BiTreebt,int*w,intx){ if(! bt) return0; if(bt) w[x]=w[x]+1; if(bt->lchild) Wide(bt->lchild,w,x+1); if(bt->rchild) Wide(bt->rchild,w,x+1); return0; }//Wide 求二叉树的宽度,递归调用,先求得其高度,创建一个数组输入,并输入其层数。 若双亲非空w[x]++。 调用其左右孩子。 这样就可以得到每层的宽度,找到最大值就是二叉树的宽度。 voidCopyBiTree(BiTree&P,BiTreeQ){ BiTreelp,rp; if(! Q) P=NULL; else{ CopyBiTree(lp,Q->lchild); CopyBiTree(rp,Q->rchild); P=(BiTree)malloc(sizeof(BiNode)); P->data=Q->data; P->lchild=lp; P->rchild=rp; } }//CopyBiTree 复制二叉树,仍是递归调用。 从下向上、从左到右创建,当头指针为空时,赋值空指针。 intDestroyBiTree(BiTree&bt){ if(! bt) return0; if(bt->lchild) DestroyBiTree(bt->lchild); if(bt->rchild) DestroyBiTree(bt->rchild); if(! bt->lchild&&! bt->rchild){ free(bt); bt=NULL; return0; } return0; }//DestroyBiTree 销毁二叉树,递归调用。 如果头指针为空,返回。 调用左右孩子,如果左右孩子为空,释放双亲。 开始先判断左右孩子是否非空,程序很长。 经过调整,最后判断,使函数大大缩减了。 intCalculate(BiTreebt){ intl,r; if(! bt->lchild&&! bt->rchild) returnbt->data-48; l=Calculate(bt->lchild); r=Calculate(bt->rchild); switch(bt->data){ case'+': returnl+r; case'-': returnl-r; case'*': returnl*r; case'/': returnl/r; } return0; }//Calculate 计算二叉树的值,递归调用。 如果左右孩子为空,返回其ASCII码-48,即其实数值。 开始不是在返回时减去48,而是在计算时减去,不好操作,最后改在返回时减去48。 计算左孩子值和右孩子值,根据算数符号返回相应的值。 intRestore(BiTreebt){ if(! bt) return0; if((bt->data=='*'||bt->data=='/')&&(bt->lchild->data=='+'||bt->lchild->data=='-')){ printf("("); Restore(bt->lchild); printf(")"); } else{ Restore(bt->lchild); } Visit(bt->data); if((bt->data=='*'||bt->data=='/')&&(bt->rchild->data=='+'||bt->rchild->data=='-')){ printf("("); Restore(bt->rchild); printf(")"); } else{ Restore(bt->rchild); } return0; }//Restore 还原二叉树,利用中序遍历。 如果双亲是*或者/,左孩子是+或-,则在打印左孩子两边加上()。 否则直接打印。 中间打印双亲。 右孩子同理。 /*====================main====================*/ voidmain(){ intn,m,i,j,x,y; char*p; char*q; int*w; BiTreeS[10]; for(i=0;i<10;i++) S[i]=NULL; printf("二叉树运算器\n"); printf("说明: 共有十个二叉树备用位置: 0~9.\n菜单: \n0\t退出\n1\t创建二叉树\n2\t遍历二叉树\n3\t二叉树结点数\n4\t二叉树叶子数\n5\t二叉树高度\n6\t二叉树宽度\n7\t二叉树每层宽度\n8\t复制二叉树\n9\t销毁二叉树\n10\t还原中缀式\n11\t二叉树求值\n"); printf("请输入命令: "); scanf("%d",&n); while(n){ switch(n){ case1: printf("1.创建方式: \n (1)\t扩展先序\n (2)\t扩展后序(从左到右输入)\n(3)\t扩展后序(从右到左输入)\n(4)\t先序+中序\n(5)\t中序+后序\n请选择("); scanf("%d",&n); printf("(%d)请选择创建位置: ",n); scanf("%d",&i); while (1){ if(i>9||i<0){ printf("位置选择错误! 请重新选择存储位置(0-9): "); scanf("%d",&i); } elseif(S[i]){ printf("已占用! 请重新选择存储位置: "); scanf("%d",&i); } else break; } switch(n){ case1: printf(" (1)请输入扩展先序序列: "); S[i]=PreCreateBiTree(); break; case2: printf(" (2)请输入扩展后序序列(从左到右输入): "); PostCreateBiTree1(S[i]); break; case3: printf("(3)请输入扩展后序序列(从右到左输入): "); S[i]=PostCreateBiTree2(); break; case4: printf("(4)请输入结点数: "); scanf("%d",&x); p=(char*)malloc(x*sizeof(char)); if(! p)exit (1); q=(char*)malloc(x*sizeof(char)); if(! q)exit (1); printf("(4)请输入先序序列: "); for(j=0;j p[j]=getchar(); p[j]=getchar(); } printf("(4)请输入中序序列: "); for(j=0;j q[j]=getchar(); q[j]=getchar(); } Pre_InCreate(S[i],p,q,x); break; case5: printf("(5)请输入结点数: "); scanf("%d",&x); p=(char*)malloc(x*sizeof(char)); if(! p)exit (1); q=(char*)malloc(x*sizeof(char)); if(! q)exit (1); printf("(5)请输入中序序列: "); for(j=0;j p[j]=getchar(); p[j]=getchar(); } printf("(5)请输入后序序列: "); for(j=0;j q[j]=getchar(); q[j]=getchar(); } In_PostCreate(S[i],p,q,x); free(p); free(q); break; } printf("1.创建完成.\n"); break; case2: printf("2.遍历方式: \n (1)\t先序遍历\n (2)\t中序遍历\n(3)\t后序遍历\n(4)\t按层遍历\n(5)\t全部显示\n请选择("); scanf("%d",&n); printf("(%d)请选择遍历位置: ",n); scanf("%d",&i); if(! S[i]){ printf("NULL\n"); break; } switch(n){ case1: pr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 二叉 运算器 实验 报告