数据结构大作业平衡二叉树.docx

上传人:b****6 文档编号:7215227 上传时间:2023-01-21 格式:DOCX 页数:24 大小:95.03KB
下载 相关 举报
数据结构大作业平衡二叉树.docx_第1页
第1页 / 共24页
数据结构大作业平衡二叉树.docx_第2页
第2页 / 共24页
数据结构大作业平衡二叉树.docx_第3页
第3页 / 共24页
数据结构大作业平衡二叉树.docx_第4页
第4页 / 共24页
数据结构大作业平衡二叉树.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

数据结构大作业平衡二叉树.docx

《数据结构大作业平衡二叉树.docx》由会员分享,可在线阅读,更多相关《数据结构大作业平衡二叉树.docx(24页珍藏版)》请在冰豆网上搜索。

数据结构大作业平衡二叉树.docx

数据结构大作业平衡二叉树

数学与计算机学院计算机系数据结构程序设计报告

 

平衡二叉树

 

学生姓名:

**

学好:

1004681028

班级:

计算机系102

指导老师:

***

报告日期:

2011/6/26

 

1.平衡二叉树…………………………………………………3

1.1平衡二叉树的定义…………………………………...3

1.2平衡二叉树的构造…………………………………...3

1.3平衡二叉树查找的分析……………………………...3

2.程序功能……………………………………………………3

3.程序结构类型………………………………………………3

4.程序函数……………………………………………………4

5.算法思想……………………………………………………5

5.1判断二叉树的旋转方法……………………………...5

5.2平衡旋转处理………………………………………...5

5.3在平衡二叉树中插入元素…………………………...5

5.4在平衡二叉树中删除元素………………………...…5

5.5输出平衡二叉树树形………………………………...5

5.6销毁平衡二叉树……………………………………...5

6.程序设计总结……………………………………………….9

7.结束语………………………………………………………10

8.附录:

程序清单……………………………………………10

1.平衡二叉树

1.1平衡二叉树的定义

平衡二叉树(BalancedBinaryTree或Height-BalancedTree)又称AVL树。

它或者是一颗空树,或者是具有下列性质的二叉树:

它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。

若将二叉树上结点的平衡因子BF(BalancedFactor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子之可能是-1、0和1。

只要二

叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。

1.2平衡二叉树的构造

构造一颗平衡二叉树的过程就是将一颗空树从根结点起,逐步插入或删除结点并不断对此树进行平衡化。

在构造平衡二叉树的过程中有插入和删除两大操作。

在树中进行插入和删除操作都可使树失去平衡,然而要让二叉排序树由不平衡转化为平衡,操作就是对二叉树进行旋转,旋转的过程将在算法思想中详细介绍。

1.3平衡二叉树查找的分析

在平衡二叉树上进行查找的过程和二叉排序树相同,因此,在查找过程中和给定值进行比较的关键字个数不超过树的深度。

因此,在平衡二叉树上进行查找的时间复杂度为O(logn).

2.程序功能

本程序的功能就是将二叉排序树转变为平衡二叉树,其操作有:

创建二叉树、插入数据、

删除数据、输出、销毁二叉树和退出。

1——创建二叉树

2——插入数据

3——删除数据

4——输出

5——销毁二叉树

0——退出

请选择:

 

3.程序结构类型

在本程序中主要用到两个结构类型:

结构体和队列。

二叉树是链式存储结构,故用结构

体来定义其结构。

队列是用作输出二叉树的树形(层序输出)。

4.程序函数

4.1main()函数:

(1)函数原形:

voidmain()

(2)功能:

显示总菜单,调用子函数

4.2Create()函数:

(1)函数原形:

voidCreate(BSTree&T)

(2)功能:

实现二叉树的创建

4.3Insert()函数:

(1)函数原形:

voidInsert(BSTree&T)

(2)功能:

实现在二叉树中插入数据

4.4InsertAVL()函数:

(1)函数原形:

intInsertAVL(BSTree&T,inte,int&taller)

(2)功能:

插入结点,并将二叉树平衡化

4.5DeleteMenu()函数:

(1)函数原形:

voidDeleteMenu(BSTree&T)

(2)功能:

实现在二叉树中删除数据

4.6DeleteAVL()函数:

(1)函数原形:

intDeleteAVL(BSTree&T,inte,int&shorter)

(2)功能:

删除结点,并将二叉树平衡化

4.7Delete()函数:

(1)函数原形:

intDelete(BSTree&p)

(2)功能:

实现删除结点

4.8Search()函数:

(1)函数原形:

voidSearch(BSTree&T,inte,intkey)

(2)功能:

在树中查找和关键字相等的结点

4.9R_Rotate()函数:

(1)函数原形:

voidR_Rotate(BSTree&p)

(2)功能:

对以*p为根结点的子树进行右旋平衡处理

4.10L_Rotate()函数:

(1)函数原形:

voidL_Rotate(BSTree&p)

(2)功能:

对以*p为根结点的子树进行左旋平衡处理

4.11RightBalance()函数:

(1)函数原形:

intRightBalance(BSTree&T)

(2)功能:

对以指针T所指结点为根的二叉树作右平衡旋转处理

4.12LeftBalance()函数:

(1)函数原形:

intLeftBalance(BSTree&T)

(2)功能:

对以指针T所指结点为根的二叉树作左平衡旋转处理

4.13Output()函数:

(1)函数原形:

voidOutput(BSTreeT)

(2)功能:

将二叉树按中序和层序输出

4.14Inordertraverse()函数:

(1)函数原形:

voidInordertraverse(BSTreeT)

(2)功能:

将二叉树按中序输出

4.15Depth()函数:

(1)函数原形:

voidDepth(BSTreep,intn,int&num)

(2)功能:

求二叉树的深度

4.16Levelordertraverse()函数:

(1)函数原形:

intLevelordertraverse(Stack&Q)

(2)功能:

将二叉树按层序输出

4.17Initstack()函数:

(1)函数原形:

intInitstack(Stack&Q)

(2)功能:

构造一个空队列

4.18Push()函数:

(1)函数原形:

intPush(Stack&Q,BSTreee)

(2)功能:

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

4.19Pop()函数:

(1)函数原形:

intPop(Stack&Q,BSTree&q)

(2)功能:

删除对头元素

4.20Destroy()函数:

(1)函数原形:

voidDestroy(BSTree&T)

(2)功能:

将队列销毁

5.算法思想

5.1判断二叉树的旋转方法

在一颗平衡二叉树中插入或删除一个结点后,若二叉树失去平衡,则需将二叉树进行平衡化处理,简而言之,就是对不平衡的二叉树进行旋转处理。

假设在二叉排序树中插入或删除结点而失去平衡的最小子树根结点的指针为T(即T是离插入或删除结点最近,且平衡因子绝对值超过1的祖先结点),指针p指向结点T的左子树的根结点,指针q指向结点T的右子树的根结点,则判断方法如下:

(1)若结点T的平衡因子为2,结点p的平衡因子为1,则需对结点T进行单向右旋平衡处理;

(2)若结点T的平衡因子为-2,结点p的平衡因子为-1,则需对结点T进行单向左旋平衡处理;

(3)若结点T的平衡因子为2,结点p的平衡因子为-1,则需先对结点p进行单向左旋平衡处理,再对结点T进行单向右旋平衡处理,将这两步简称为对结点T进行双向旋转(先左后右)平衡处理;

(4)若结点T的平衡因子为-2,结点p的平衡因子为1,则需先对结点p进行单向右旋平衡处理,再对结点T进行单向左旋平衡处理,将这两步简称为对结点T进行双向旋转(先右后左)平衡处理;

5.2平衡旋转处理

假设由于在二叉排序树上插入或删除结点而失去平衡的最小子树根结点的指针为T(即T为里插入结点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行平衡处理有如下4种情况:

(1)单向右旋平衡处理:

若指针p指向以*T为根的左子树的根结点,将*p的右子树作为*T的左子树,再将以*T为根的树作为*p的右子树,如图(a)所示。

 

(2)单向左旋平衡处理:

若指针p指向以*T为根的右子树的根结点,将*p的左子树作为*T的右子树,再将以*T为根的树作为*p的左子树,如图(b)所示。

 

(3)双向旋转(先左后右)平衡处理:

若p指向以*T为根的左子树的根结点,q以*p为根的右子树的根结点,则先将以*p为根结点的树进行单向左旋,再将以*q为根结点的树进行单向右旋,如图(c)所示。

 

(4)双向旋转(先右后左)平衡处理:

若p指向以*T为根的右子树的根结点,q以*p为根的左子树的根结点,则先将以*p为根结点的树进行单向右旋,再将以*q为根结点的树进行单向左旋,如图(d)所示。

 

5.3在平衡二叉树BBST中插入元素

在平衡的二叉排序树上插入一个新的数据元素e:

(1)若BBST为空树,则插入一个数据元素e的新结点作为BBST的根结点,

树的深度增1;

(2)若e的关键字和BBST的根结点的关键字相等,则不进行插入;

(3)若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有

相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加

(+1)时,分别就下列不同情况处理:

①BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度):

则将根结点

的平衡因子更改为0,BBST的深度不变;

②BBST的根结点的平衡因子为0,(左、右子树的深度相等):

则将根结点的平衡因

子更改为1,BBST的深度增1;

③BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):

若BBST的左

子树的平衡因子为1,则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变;若BBST的左子树根结点的平衡因子为-1,则需进行先向左、后先向右的双向旋转平衡处理,并且在旋转处理之后,修改根结点和其左、右子树根结点的平衡因子,树的深度不变;

(4)若e的关键字大于BBST的根结点的关键字,而且BBST的右子树不存在和e有相同

关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的右子树深度增加(+1)时,分别就不同情况处理:

①BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):

则将根结点的

平衡因子更改为0,BBST的深度不变;

②BBST的根结点的平衡因子为0,(左、右子树的深度相等):

则将根结点的平衡因

子更改为-1,BBST的深度增1;

③BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度):

若BBST的

左子树的平衡因子为-1,则需进行单向左旋平衡处理,并且在左旋处理之后,将根结点和其左子树根结点的平衡因子更改为0,树的深度不变;若BBST的左子树根结点的平衡因子为1,则需进行先向右、后先向左的双向旋转平衡处理,并且在旋转处理之后,修改根结点和其左、右子树根结点的平衡因子,树的深度不变;

 

5.4平衡二叉树中删除元素

假设在平衡二叉树上删除结点为*p(指向结点的指针为p),其双亲结点为*f(结点指针为f),且不失一般性,可设*p是*f的左孩子:

(1)若*p结点为叶子结点,则直接将*p结点删除,如图(e)所示。

 

(2)若*p结点只有左子树或者只有右子树,此时只要令*p的左子树或右子树成为其双亲结点*f的左子树,如图(f)所示;

 

(2)若*p结点的左子树和右子树均不空,则令*p的直接前驱代替*p,然后再从二叉排序树中删去它的直接前驱,如图(g)所示;

 

在上述三种删除*p结点的处理后,若二叉树仍然平衡,则只需修改*f结点的平衡因子;否则,则需从*p结点回溯到根结点,找到回溯途中遇到的不平衡结点,并将其平衡化;将删除结点后不平衡树平衡化的具体处理方法如下:

设p为回溯至根结点的路径上的某一结点

①结点p的平衡因子为0,若删除结点为p结点左子树上的结点,则将结点p的平衡因子改为-1,并相应将树平衡化;若删除结点为p结点右子树上的结点,则将结点p的平衡因子改为1,并相应将树平衡化。

无论删除结点为p结点左子树或右子树上的结点,都不需要再向根结点回溯,平衡处理结束;

②结点p的平衡因子为1,若删除结点为p结点左子树上的结点,则将结点p的平衡因子该为0,再从结点p向根结点回溯;若删除结点为p结点右子树上的结点,设q指向p的左子树的根结点,则需将结点p进行单向右旋处理,并相应修改各结点的平衡因子,再从结点p向根结点回溯;

③结点p的平衡因子为-1,若删除结点为p结点左子树上的结点,设q指向p的右子树的根结点,则需将结点p进行单向左旋处理,并相应修改各结点的平衡因子,再从结点p向根结点回溯;若删除结点为p结点右子树上的结点,则将结点p的平衡因子该为0,再从结点p向根结点回溯;

特别需要注意的是,在平衡二叉树中删除一个结点后使不平衡根结点的平衡因子变为2或-2,根结点的左或右孩子的平衡因子为0,此时需将根结点进行单向右或左旋处理,然而旋转处理后的树的深度不变,如图(h)所示。

 

5.5输出平衡二叉树树形

将一颗平衡二叉树按树形输出,要用到队列,并且将此平衡二叉树当做满二叉树,孩子结点为空的用空字符代替。

首先,应先求出二叉树的深度n,根据完全二叉树的性质知,第n层上的结点数至多为2n-1。

此时,便可知道每层上应输出的空格数,并可以控制每层上结点之间的间距。

此外,还要控制换行,记录输出的结点数num,若num等于i层的总结点数2i-1则换行。

若树不为空,则将根结点插入到队列中,接着将根结点从队列中删除并输出,再把根结点的左、右孩子插入到队列中,若孩子结点为空则用空字符代替,重复上述操作,直到当num等于n层总结点数2n-1,则结束输出。

5.6销毁平衡二叉树

销毁平衡二叉树就是将二叉树中的每一个结点用free()函数释放,其具体过程采用递归:

将平衡二叉树的根结点的指针T传到销毁函数,如果*T结点的左孩子不为空,则将*T结点的左子树的根结点进行递归,直到结点的左孩子为空;再判断结点的右孩子是否为空,若不为空则将结点的右子树的根结点进行递归,直到结点的右子树为空;最后将结点的指针赋为空指针。

 

6.程序设计总结

将一颗二叉排序树转变为平衡二叉树并将平衡树按树形输出的算法,主要操作就是插入、删除和输出。

本人在编写插入算法,经过陈老师的讲解和课后的思考,根据书本上的算法编写完成。

然而,在二叉树中删除结点,本人是在网上以及图书馆书籍上查找的。

很令人失望的是,网上和书籍里对于在二叉树中删除结点再将其平衡化的算法思想介绍很少,甚至有些书籍上根本就没提及过。

看着做的一点笔记,本人还是很是不知所措,不懂其算法思想,经过三天的思索,终于有些头绪,尝试着编写,尽管失败了很多次,但总算勉强写出了算法。

(我所编写的算法可能和书籍中讲解的不同,只是换了一种实现方法。

)至于将二叉树按树形输出,是在陈老师的指导下写出的,陈老师告诉我算法思想,之后就在思想的指导下完成了算法。

能完成这个程序,我还是感到挺高兴的,在今后我也会一如既往,认真努力学习,不断提升自己,实现自己的理想。

7.结束语

在此,我很是感谢陈老师,他在我学习的途中给了我很多的帮助,让我懂得很多东西,学会很多,真心感谢他。

同时,我也要对平时帮助我的同学表示感谢。

在我人生的道路中,很多人在我失意时帮我走出阴霾,感谢他们。

8.附录:

程序清单

#include

#include

#include

#defineOK1

#defineERROR0

#defineLH1

#defineEH0

#defineRH-1

typedefstructBSTNode{

intdata;

intbf;

structBSTNode*lchild,*rchild;

}BSTNode,*BSTree;

typedefstruct{

BSTreep;

}elem,*Elem;

typedefstruct{

Elembase;

Elemtop;

}Stack;

inth,num,m,k,t,key=0;

BSTreew;

voidCreate(BSTree&T);

voidInsert(BSTree&T);

intInsertAVL(BSTree&T,inte,int&taller);

voidR_Rotate(BSTree&p);

voidL_Rotate(BSTree&p);

intLeftBalance(BSTree&T);

intRightBalance(BSTree&T);

voidDeleteMenu(BSTree&T);

intDeleteAVL(BSTree&T,inte,int&shorter);

intDelete(BSTree&p);

voidSearch(BSTree&T,inte,intkey);

voidOutput(BSTreeT);

voidInordertraverse(BSTreeT);

voidDepth(BSTreep,intn,int&num);

intLevelordertraverse(Stack&Q);

intInitstack(Stack&Q);

intPush(Stack&Q,BSTreee);

intPop(Stack&Q,BSTree&q);

voidDestroy(BSTree&T);

voidmain(){

inta=1,flag=0;

BSTreeT=NULL;

while(a){

system("cls");

printf("\n\n\n\n\n\t\t\t\t1——创建二叉树\n\n\n\n");

printf("\t\t\t\t2——插入数据\n\n\n\n");

printf("\t\t\t\t3——删除数据\n\n\n\n");

printf("\t\t\t\t4——输出\n\n\n\n");

printf("\t\t\t\t5——销毁二叉树\n\n\n\n");

printf("\t\t\t\t0——退出\n\n");

if(!

flag)

printf("\n\n\n\n请选择:

");

else{

printf("\n\n\n\n你的输入有误,请重新输入:

");

flag=0;

}

scanf("%d",&a);

switch(a){

case1:

system("cls");Create(T);break;

case2:

system("cls");Insert(T);break;

case3:

system("cls");DeleteMenu(T);break;

case4:

system("cls");

if(T)

Output(T);

else{

printf("此二叉树为空树");

printf("\n\n\n按Enter→");

getchar();getchar();

}

break;

case5:

system("cls");Destroy(T);

printf("已将此二叉树销毁\n\n\n\n");

printf("\n\n\n按Enter→");

getchar();getchar();

case0:

system("cls");printf("\n\n\n\n\n\n\n\n\n\n\t\t\t\t\tTHANKS\n\n\n\n\n\n\n\n\n\n\n\n");break;

default:

flag=1;break;

}

}

}

voidCreate(BSTree&T){

inta=1,s,taller=false;

while(a){

printf("请输入数据(0结束):

");

scanf("%d",&a);

if(a){

s=InsertAVL(T,a,taller);

if(!

s)

printf("%d已存在二叉树中",a);

}

printf("\n\n");

}

}

voidInsert(BSTree&T){

inta,s,taller=false;

printf("请输入数据:

");

scanf("%d",&a);

do{

s=InsertAVL(T,a,taller);

if(s)

printf("\n\n%d已插入到二叉树中",a);

else{

system("cls");

printf("%d已存在二叉树中,请重新输入:

",a);

scanf("%d",&a);

}

}while(!

s);

printf("\n\n\n\n\n\n\n按Enter→");

getchar();getchar();

}

intInsertAVL(BSTree&T,inte,int&taller){

if(!

T){

T=(BSTree)malloc(sizeof(BSTNode));

if(!

T)

exit(-1);

T->data=e;T->bf=EH;T->lchild=T->rchild=NULL;

taller=true;

}

else{

if(e==T->data){

taller=false;

return0;

}

elseif(edata){

if(!

InsertAVL(T->lchild,e,taller))

return0;

if(taller){

switch(T->bf){

caseLH:

LeftBalance(T);taller=false;break;

caseEH:

T->bf=LH;taller=true;break;

caseRH:

T->bf=EH;taller=false;break;

}

}

}

else{

if(!

InsertAVL(T->rchild,e,taller))

return0;

if(taller){

switch(T->bf){

caseLH:

T->bf=EH;taller=false;break;

caseEH:

T->bf=RH;taller=true;break;

caseRH:

RightBalance(T);taller=f

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

当前位置:首页 > 表格模板 > 合同协议

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

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