数据结构二叉树运算器实验报告.docx

上传人:b****5 文档编号:8306716 上传时间:2023-01-30 格式:DOCX 页数:21 大小:20.85KB
下载 相关 举报
数据结构二叉树运算器实验报告.docx_第1页
第1页 / 共21页
数据结构二叉树运算器实验报告.docx_第2页
第2页 / 共21页
数据结构二叉树运算器实验报告.docx_第3页
第3页 / 共21页
数据结构二叉树运算器实验报告.docx_第4页
第4页 / 共21页
数据结构二叉树运算器实验报告.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

数据结构二叉树运算器实验报告.docx

《数据结构二叉树运算器实验报告.docx》由会员分享,可在线阅读,更多相关《数据结构二叉树运算器实验报告.docx(21页珍藏版)》请在冰豆网上搜索。

数据结构二叉树运算器实验报告.docx

数据结构二叉树运算器实验报告

二叉树运算器

一、问题描述

本实验主要实现对二叉树的多种方式创建、多种方式遍历、复制、销毁,求二叉树的结点数、叶子数、高度、宽度、每层宽度,用二叉树对中缀式还原,用二叉树进行求值。

二、存储结构

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

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

当前位置:首页 > 总结汇报 > 学习总结

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

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