二叉树、平衡二叉树、红黑树、B-树、B+树、B*树、T树之间的详解和比较

====================================================||

欢迎讨论技术的可以相互加微信:windgs (请备注csdn+xx职业)

====================================================||

 

一、二叉树-BST  (binary search/sort tree)

二叉树又名二叉查找/搜索/排序树  
或者是一棵空树
或者是具有下列性质的二叉树:
(1)若它的左子树不空,则左子树上所有结点的值均小于它的父结点的值;
(2)若它的右子树不空,则右子树上所有结点的值均大于它的父结点的值;
(3)它的左、右子树也分别为二叉排序树。
遍历:分为前序遍历中序遍历得到有序集合)、后续遍历

1.所有非叶子结点至多拥有两个儿子(Left和Right);

2.所有结点存储一个关键字;

3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

 BST树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;

否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入

右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;

       如果BST树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树

的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变BST树结构

(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销;

右边也是一个BST树,但它的搜索性能已经是线性的了;同样的关键字集合有可能导致不同的

树结构索引;所以,使用BST树还要考虑尽可能让BST树保持左图的结构,和避免右图的结构,也就

是所谓的“平衡”问题;

二、平衡二叉树(Self-balancing binary search tree)  

自平衡二叉查找树  又被称为AVL树(有别于AVL算法)
它是一棵空树或它的左右两个子树的高度差(平衡因子)的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,平衡二叉树必定是二叉搜索树,反之则不一定

 平衡因子(平衡度):平衡度为1,既每个结点的平衡因子都为 1、-1、0 的二叉排序树。或者说每个结点的左右子树的高度最多差1的二叉排序树。

平衡二叉树的目的是为了减少二叉查找树层次,提高查找速度

平衡二叉树的常用实现方法有AA树AVL树红黑树、树堆Treap、伸展树

AVL 树是高度平衡的,频繁的插入和删除,会引起频繁的reblance,导致效率下降
红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转

AVL平衡二叉搜索树
定义:平衡二叉树或为空树,或为如下性质的二叉排序树:
  (1)左右子树深度之差的绝对值不超过1;
  (2)左右子树仍然为平衡二叉树.
平衡因子BF=左子树深度-右子树深度.
平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。
如图所示为平衡树和非平衡树示意图:

三、红黑树-R-B Tree,全称是Red-Black Tree

又称为“红黑树”,它一种平衡二叉树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

注意:
(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树

四、B-树是一种多路搜索树(并不一定是二叉的)

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。它或者是空树,或者是满足下列性质的树:
1、根结点至少有两个子女;

2、每个非根节点所包含的关键字个数 j 满足:┌m/2┐ - 1 <= j <= m - 1;

3、除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:┌m/2┐ <= k <= m ;

4、所有的叶子结点都位于同一层。

特点:
是一种多路搜索树(并不是二叉的):

1.定义任意非叶子结点最多只有M个儿子;且M>2;

2.根结点的儿子数为[2, M];

3.除根结点以外的非叶子结点的儿子数为[M/2, M];

4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)

5.非叶子结点的关键字个数=指向儿子的指针个数-1;

6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];

7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的

子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;

8.所有叶子结点位于同一层;

如:(M=3)

B-树的特性:

1.关键字集合分布在整颗树中;

2.任何一个关键字出现且只出现在一个结点中;

3.搜索有可能在非叶子结点结束;

4.其搜索性能等价于在关键字全集内做一次二分查找;

5.自动层次控制;

五、B+树

B+ 树是一种树数据结构,是一个n叉树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。

用途:

B+ 树通常用于数据库和操作系统的文件系统中。NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等文件系统都在使用B+树作为元数据索引。B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入。

B+树的定义

B+树是应文件系统所需而出的一种B-树的变型树。一棵m阶的B+树和m阶的B-树的差异在于:
1.有n棵子树的结点中含有n个关键字,每个关键字不保存数据,只用来索引,所有数据都保存在叶子节点。

2.所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

3.所有的非终端结点可以看成是索引部分,结点中仅含其子树(根结点)中的最大(或最小)关键字。 
通常在B+树上有两个头指针,一个指向根结点,一个指向关键字最小的叶子结点。

B+树是B-树的变体,也是一种多路搜索树:

1.其定义基本与B-树同,除了:

2.非叶子结点的子树指针与关键字个数相同;

3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树

(B-树是开区间);

5.为所有叶子结点增加一个链指针

6.所有关键字都在叶子结点出现;
 

B+的特性:

1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好

是有序的;

2.不可能在非叶子结点命中;

3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储

(关键字)数据的数据层;

4.更适合文件索引系统;

六、B*树:

是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;

B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3
(代替B+树的1/2);

B+树的分裂:

当一个结点满时,分配一个新的结点,并将原结点中1/2的数据

复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父

结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;

B*树的分裂:

当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分

数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字

(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之

间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针

所以,B*树分配新结点的概率比B+树要低,空间使用率更高;

七、T-tree树-一个存储节点可以保存多个键值

1.T树相关概念
     T树具有以下特点:

①左子树与右子树之差不超过1

②在一个存储节点可以保存多个键值它的最左与最右键值分别为这个节点的最小与最大键值,它的左子树仅仅包含那些键值小于或等于最小键值的一记录,同理右子树只包括那些键值大于或等于最大键值的记录

③同时拥有左右子树的节点被称为内部节点,只拥有一个子树的节点被称为半叶一,没有子树的节点被称为叶子

④为了保持空间的利用率,每一个内部节点都需要包含一个最小数目的键值。由此可知T树是一个每个结点含有多个关键字平衡二叉树,每个节点内的关键字有序排列,左子树都要比根节点关键字小,右子树都要比根节点关键字大。
在上述T树结点结构中,包含如下信息:
(1) balance(平衡因子),其绝对值不大于1,balance =右子树高度-左子树高度;
(2) Left_child_ptr和Right_child_ptr分别表示当前结点的左子树和右子树指针;
(3) Max_Item表示结点中所能容纳的键值的最大数;
(4)Key[0]至K[Max_Item-1]为结点内存放的关键字;
(5)nItem是当前节点实际存储的关键字个数。


2.T树索引的操作
      用T树作为索引方式主要完成三个工作:查找,插入,删除。其中插入和删除都是以查找为基础。下面分别介绍三种操作的流程。
(1)T树的查找类似于二叉树,不同之处主要在于每一结点上的比较不是针对结点中的各个元素值,而是首先检查所要查找的目标键值是否包含在当前结点的最左键值和最右键值所确定的范围内,如果是的话,则在当前结点的键值列表中使用二分法进行查找;如果目标键值小于当前结点的最左键值,则类似地搜索当前结点的左孩子结点;如果目标键值大于当前结点的最右键值,则类似地搜索当前结点的右孩子结点。 
(2)T树的插入是以查找为基础,应用查找操作定位目标键值插入位置,并记下查找过程所遇到的最后结点。如果查找成功,判断此结点中是否有足够的存储空间。如果有,则将目标键值插入结点中;否则将目标键值插入此结点,然后将结点中的最左键值插入到它的左子树中(此时是递归插入操作),之后结束;否则分配新结点,并插入目标键值;然后根据目标键值与结点的最大最小键值之间的关系,将新分配的结点链接为结点的左孩子或右孩子;对树进行检查,判断T树的平衡因子是否满足条件,如果平衡因子不满足则执行旋转操作。

(3)T树的删除操作也是以查找为基础,应用查找操作定位目标键值。如果查找失败,则结束;否则令N为目标键值所在的结点,并从结点N中删除目标键值;删除节点后,如果结点N为空,则删除结点N,并对树的平衡因子进行检查,判断是否需要执行旋转操作;如果结点N中的键值数量少于最小值,则根据N的平衡因子决定从结点N的左子树中移出最大的键值或者右子树中移出最小值来填充。 

3.T树索引实现关键技术
     实现T树索引即要实现T树的查找,插入和删除。其中又以查找为基础,对T树的维护也就是T树的旋转为关键。当由于插入或删除键值导致树的失衡,则要进行T树的旋转。使之重新达到平衡。
     在插入情况下,需要依次对所有沿着从新创建结点到根结点路径中的结点进行检查,直到出现如下两种情况之一时中止:某个被检查结点的两个子树高度相等,此时不需要执行旋转操作;某个被检查结点的两个子树的高度之差大于1,此时对该结点仅需执行一次旋转操作即可。
     在删除情况下,类似地需要依次对所有沿着从待删除结点的父结点到根结点路径中的结点进行检查,在检查过程中当发现某个结点的左右子树高度之差越界时,需要执行一次旋转操作。与插入操作不同的是,执行完旋转操作之后,检查过程不能中止,而是必须一直执行到检查完根结点。
     由此可以看出,对于插入操作,最多只需要一次旋转操作即可使T树恢复到平衡状态;而对于删除操作则可能会引起向上的连锁反应,使高层结点发生旋转,因而可能需要进行多次旋转操作
     为了对T树进行平衡,需要进行旋转操作,旋转是T树中最关键也是最难的的操作,下面介绍T树旋转的技术。

旋转可分为四种情况:由左孩子的左子树的插入(或者删除)引起的旋转记为LL旋转,类似有LR,RR及RL旋转。插入时的情况与删除类似。

八、R-tree-空间索引数据结构

1、R-Tree数据结构
R-Tree是一种空间索引数据结构,下面做简要介绍:

(1)R-Tree是n 叉树,n称为R-Tree的扇(fan)。

(2)每个结点对应一个矩形。

(3)叶子结点上包含了小于等于n 的对象,其对应的矩为所有对象的外包矩形。

(4)非叶结点的矩形为所有子结点矩形的外包矩形。

R-Tree的定义很宽泛,同一套数据构造R-Tree,不同方可以得到差别很大的结构。什么样的结构比较优呢?有两标准:

(1)位置上相邻的结点尽量在树中聚集为一个父结点。

(2)同一层中各兄弟结点相交部分比例尽量小。

R树是一种用于处理多维数据的数据结构,用来访问二维或者更高维区域对象组成的空间数据.R树是一棵平衡树。树上有两类结点:叶子结点和非叶子结点。每一个结点由若干个索引项构成。对于叶子结点,索引项形如(Index,Obj_ID)。其中,Index表示包围空间数据对象的最小外接矩形MBR,Obj_ID标识一个空间数据对象。对于一个非叶子结点,它的索引项形如(Index,Child_Pointer)。 Child_Pointer 指向该结点的子结点。Index仍指一个矩形区域,该矩形区域包围了子结点上所有索引项MBR的最小矩形区域。


2、R-Tree空间索引算法

1、R-Tree-最小外接矩形

多维索引技术的历史可以追溯到20世纪70年代中期。就在那个时候,诸如Cell算法、四叉树和k-d树等各种索引技术纷纷问世,但它们的效果都不尽人意。在GIS和CAD系统对空间索引技术的需求推动下,Guttman于1984年提出了R树索引结构,发表了《R树:一种空间查询的动态索引结构》,它是一种高度平衡的树,由中间节点和页节点组成,实际数据对象的最小外接矩形存储在页节点中中间节点通过聚集其低层节点的外接矩形形成,包含所有这些外接矩形。其后,人们在此基础上针对不同空间运算提出了不同改进,才形成了一个繁荣的索引树族,是目前流行的空间索引。

2、 R+树-兄弟结点对应的空间区域无重叠

在Guttman的工作的基础上,许多R树的变种被开发出来, Sellis等提出了R+树,R+树与R树类似,主要区别在于R+树中兄弟结点对应的空间区域无重叠,这样划分空间消除了R树因允许结点间的重叠而产生的“死区域”(一个结点内不含本结点数据的空白区域),减少了无效查询数,从而大大提高空间索引的效率,但对于插入、删除空间对象的操作,则由于操作要保证空间区域无重叠而效率降低。同时R+树对跨区域的空间物体的数据的存储是有冗余的,而且随着数据库中数据的增多,冗余信息会不断增长。Greene也提出了他的R树的变种。

3 R*树-强制重新插入

在1990年,Beckman和Kriegel提出了最佳动态R树的变种——R*树。R*树和R树一样允许矩形的重叠,但在构造算法R*树不仅考虑了索引空间的“面积”,而且还考虑了索引空间的重叠。该方法对结点的插入、分裂算法进行了改进,并采用“强制重新插入”的方法使树的结构得到优化。但R*树算法仍然不能有效地降低空间的重叠程度,尤其是在数据量较大、空间维数增加时表现的更为明显。R*树无法处理维数高于20的情况。

4 QR树-四叉树-结合了四叉树与R树的优势,是二者的综合应用

QR树利用四叉树将空间划分成一些子空间,在各子空间内使用许多R树索引,从而改良索引空间的重叠。QR树结合了四叉树与R树的优势,是二者的综合应用。实验证明:与R树相比,QR树以略大(有时甚至略小)的空间开销代价,换取了更高的性能,且索引目标数越多,QR树的整体性能越好。

5 SS树-用最小边界圆代替最小边界矩

SS树对R*树进行了改进,通过以下措施提高了最邻近查询的性能:用最小边界圆代替最小边界矩形表示区域的形状,增强了最邻近查询的性能,减少将近一半存储空间;SS树改进了R*树的强制重插机制。当维数增加到5是,R树及其变种中的边界矩形的重叠将达到90%,因此在高维情况(≧5)下,其性能将变的很差,甚至不如顺序扫描。

6 X树-用边界圆进行索引

X树是线性数组和层状的R树的杂合体,通过引入超级结点,大大地减少了最小边界矩形之间的重叠,提高了查询效率。X树用边界圆进行索引,边界矩形的直径(对角线)比边界圆大,SS树将点分到小直径区域。由于区域的直径对最邻近查询性能的影响较大,因此SS树的最邻近查询性能优于R*树;边界矩形的平均容积比边界圆小,R*树将点分到小容积区域;由于大的容积会产生较多的覆盖,因此边界矩形在容积方面要优于边界圆。SR树既采用了最小边界圆(MBS),也采用了最小边界矩形(MBR),相对于SS树,减小了区域的面积,提高了区域之间的分离性,相对于R*树,提高了邻近查询的性能。
=============================================================================================

小结:

B树:二叉树,每个结点只存储一个关键字等于则命中小于走左结点大于走右结点

B-树多路搜索树,每个结点存储M/2到M个关键字非叶子结点存储指向关键字范围的子结点;所有关键字整颗树中出现,且只出现一次非叶子结点可以命中

B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中

B*树:在B+树基础上,为非叶子结点也增加兄弟节点链表指针,将结点的最低利用率从1/2提高到2/3;

B+/B*Tree应用:数据库索引--索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。数据库索引--表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键

攀枝花学院本科学生课程设计任务书 题 目 二叉排序平衡二叉树的实现 1、课程设计的目的 使学生进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法。 使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。 3) 使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。 2、课程设计的内容和要求(包括原始数据、技术要求、工作要求等) (1) (1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序T; (2)对二叉排序T作中序遍历,输出结果; (3)计算二叉排序T查找成功的平均查找长度,输出结果; (4)输入元素x,查找二叉排序T,若存在含x的结点,则删该结点,并作中序遍历(执行操作2);否则输出信息“无x”; (5)用数列L,生成平衡的二叉排序BT:当插入新元素之后,发现当前的二叉排序BT不是平衡的二叉排序,则立即将它转换成新的平衡的二叉排序BT; (6)计算平衡的二叉排序BT的平均查找长度,输出结果。 3、主要参考文献 [1]刘大有等,《数据结构》(C语言版),高等教育出版社 [2]严蔚敏等,《数据结构》(C语言版),清华大学出版社 [3]William Ford,William Topp,《Data Structure with C++》清华大学出版社 [4]苏仕华等,数据结构课程设计,机械工业出版社 4、课程设计工作进度计划 第1天 完成方案设计与程序框图 第2、3天 编写程序代码 第4天 程序调试分析和结果 第5天 课程设计报告和总结 指导教师(签字) 日期 年 月 日 教研室意见: 年 月 日 学生(签字): 接受任务时间: 年 月 日 注:任务书由指导教师填写。 课程设计(论文)指导教师成绩评定表 题目名称 二叉排序平衡二叉树的实现 评分项目 分值 得分 评价内涵 工作 表现 20% 01 学习态度 6 遵守各项纪律,工作刻苦努力,具有良好的科学工作态度。 02 科学实践、调研 7 通过实验、试验、查阅文献、深入生产实践等渠道获取与课程设计有关的材料。 03 课题工作量 7 按期圆满完成规定的任务,工作量饱满。 能力 水平 35% 04 综合运用知识的能力 10 能运用所学知识和技能去发现与解决实际问题,能正确处理实验数据,能对课题进行理论分析,得出有价值的结论。 05 应用文献的能力 5 能独立查阅相关文献和从事其他调研;能提出并较好地论述课题的实施方案;有收集、加工各种信息及获取新知识的能力。 06 设计(实验)能力,方案的设计能力 5 能正确设计实验方案,独立进行装置安装、调试、操作等实验工作,数据正确、可靠;研究思路清晰、完整。 07 计算及计算机应用能力 5 具有较强的数据运算与处理能力;能运用计算机进行资料搜集、加工、处理和辅助设计等。 08 对计算或实验结果的分析能力(综合分析能力、技术经济分析能力) 10 具有较强的数据收集、分析、处理、综合的能力。 成果 质量 45% 09 插图(或图纸)质量、篇幅、设计(论文)规范化程度 5 符合本专业相关规范或规定要求;规范化符合本文件第五条要求。 10 设计说明书(论文)质量 30 综述简练完整,有见解;立论正确,论述充分,结论严谨合理;实验正确,分析处理科学。 11 创新 10 对前人工作有改进或突破,或有独特见解。 成绩 指导教师评语 指导教师签名: 年 月 日 摘要及关键字 本程序中的数据采用“形结构”作为其数据结构。具体采用的是“二叉排序”。 二叉排序(又称二叉查找):(1)若左子不空,则左子上所有节点的值均小于它的根结点的值;(2)若右子不空,则右子上所有节点均大于它的根结点的值;(3)它的左右子分别为二叉排序。 二叉平衡树:若不是空,则(1)左右子都是平衡二叉树;(2)左右子的深度之差的绝对值不超过1。 本次实验是利用二叉排序平衡二叉树达到以下目的:(1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序T;(2)对二叉排序T作中序遍历,输出结果;(3)计算二叉排序T查找成功的平均查找长度,输出结果; (4)输入元素x,查找二叉排序T,若存在含x的结点,则删该结点,并作中序遍历(执行操作2);否则输出信息“无x”;(5)用数列L,生成平衡的二叉排序BT:当插入新元素之后,发现当前的二叉排序BT不是平衡的二叉排序,则立即将它转换成新的平衡的二叉排序BT; (6)计算平衡的二叉排序BT的平均查找长度,输出结果。 关键字:数列L,结点,二叉排序,平衡二叉树        目录 摘要…………………………………………………………………………… 3 1 绪论………………………………………………………………………… 5 1.1 课程设计的目的…………………………………………………………… 5 1.2 相关知识的阐述…………………………………………………………… 5 1.2.1一位数组的存储结构…………………………………………………… 5 1.2.2建立二叉排序……………………………………………………… 5 1.2.3中序遍历二叉树………………………………………………………… 5 1.2.4平均查找长度…………………………………………………………… 6 1.2.5平均二叉树(AVL)…………………………………………………… 6 1.2.6平衡因子………………………………………………………………… 7 1.2.7平衡二叉树的调整方法…………………………………………………… 7 2 方案设计……………………………………………………………… 8 2.1 模块功能………………………………………………………………………8 3 算法设计…………………………………………………………………… 8 3.1 算法流程图…………………………………………………………………… 8 4 详细设计……………………………………………………………… 10 4.1 主程序………………………………………………………………… 10 4.2 定义二叉树结构……………………………………………………………… 11 4.3 建立二叉树…………………………………………………………………… 11 4.3.1二叉排序的查找…………………………………………………………11 4.3.2二叉排序的插入…………………………………………………………11 4.4 中序遍历…………………………………………………………………12 4.5 平均查找长度…………………………………………………………………12 4.6 删除节点…………………………………………………………………12 4.7 判断平衡二叉树……………………………………………………………… 13 5 调试分析………………………………………………………………………… 14 5.1 时间复杂度的分析………………………………………………………………14 5.2 运行结果………………………………………………………………… 14 5.3 结果分析………………………………………………………………… 15 6 课程设计总结…………………………………………………………………… 16 参考文献………………………………………………………………………… 17 1 绪论 1.1 课程设计的目的 (1)使学生进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法。 (2)使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。 (3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。 1.2 相关知识的阐述 1.2.1 一维数组的存储结构 建立二插排序,首先用一个一维数组记录下读入的数据,然后再用边查找边插入的方式将数据一一对应放在完全二叉树相应的位置,为空的结点用“0” 补齐。 1.2.2 建立二叉排序 二叉排序是一种动态表。其特点是:的结构通常不是一次生成的,而是在查找过程中,当中不存在关键字等于给定值的节点时再进行插入。新插入的结点一定是一个新添加的叶子节点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。 插入算法: 首先执行查找算法,找出被插结点的父亲结点; 判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入; 若二叉树为空,则首先单独生成根结点。 注意:新插入的结点总是叶子结点。 1.2.3 中序遍历二叉树 中序遍历二叉树算法的框架是: 若二叉树为空,则空操作; 否则(1)中序遍历左子(L); (2)访问根结点(V); (3)中序遍历右子(R)。 中序遍历二叉树也采用递归函数的方式,先访问左子2i,然后访问根结点i,最后访问右子2i+1.先向左走到底再层层返回,直至所有的结点都被访问完毕。 1.2.4 平均查找长度 计算二叉排序的平均查找长度时,采用类似中序遍历的递归方式,用s记录总查找长度,j记录每个结点的查找长度,s置初值为0,采用累加的方式最终得到总查找长度s。平均查找长度就等于s/i(i为中结点的总个数)。  假设在含有n(n>=1)个关键字的序列中,i个关键字小于第一个关键字,n-i-1个关键字大于第一个关键字,则由此构造而得的二叉排序在n个记录的查找概率相等的情况下,其平均查找长度为:          ASL(n,i)=[1+i*(P(i)+1)+(n-i-1)(P(n-i-1)+1)]/n 其中P(i)为含有i个结点的二叉排序的平均查找长度,则P(i)+1为查找左子中每个关键字时所用比较次数的平均值,P(n-i-1)+1为查找右子中每个关键字时所用比较次数的平均值。又假设表中n个关键字的排列是“随机”的,即任一个关键字在序列中将是第1个,或第2个,…,或第n个的概率相同,则可对上式从i等于0至n-1取平均值。最终会推导出:          当n>=2时,ASL(n)<=2(1+1/n)ln(n) 由此可见,在随机的情况下,二叉排序的平均查找长度和log(n)是等数量级的。 另外,含有n个结点的二叉排序其判定不是惟一的。对于含有同样一组结点的表,由于结点插入的先后次序不同,所构成的二叉排序的形态和深度也可能不同。 而在二叉排序上进行查找时的平均查找长度和二叉树的形态有关:  ①在最坏情况下,二叉排序是通过把一个有序表的n个结点依次插入而生成的,此时所得的二叉排序蜕化为棵深度为n的单支,它的平均查找长度和单链表上的顺序查找相同,亦是(n+1)/2。  ②在最好情况下,二叉排序在生成的过程中,的形态比较匀称,最终得到的是一棵形态与二分查找的判定相似的二叉排序,此时它的平均查找长度大约是lgn。  ③插入、删除和查找算法的时间复杂度均为O(lgn)。 1.2.5 平衡二叉树( AVL ) ①平衡二叉树(Balanced Binary Tree)是指中任一结点的左右子的高度大致相同。     ②任一结点的左右子的高度均相同(如满二叉树),则二叉树是完全平衡的。通常,只要二叉树的高度为O(1gn),就可看作是平衡的。     ③平衡的二叉排序指满足BST性质的平衡二叉树。     ④AVL中任一结点的左、右子的高度之差的绝对值不超过1。在最坏情况下,n个结点的AVL的高度约为1.44lgn。而完全平衡的二叉树高度约为lgn,AVL是最接近最优的。 1.2.6 平衡因子 二叉树上任一结点的左子深度减去右子的深度称为该结点的平衡因子,易知平衡二叉树中所有结点的因子只可能为0,-1和1。 平衡二叉排序的在平衡因子绝对值等于2时开始调整到绝对值为1或0,在平衡因子绝对值为2时,二叉排序会出现四种不同的情况的形,因此这时需要分别单独讨论来降低平衡因子。 1.2.7 平衡二叉树的调整方法   平衡二叉树是在构造二叉排序的过程中,每当插入一个新结点时,首先检查是否因插入新结点而破坏了二叉排序的平衡性,若是,则找出其中的最小不平衡子,在保持二叉排序特性的前提下,调整最小不平衡子中各结点之间的链接关系,进行相应的旋转,使之成为新的平衡子。具体步骤如下: (1)每当插入一个新结点,从该结点开始向上计算各结点的平衡因子,即计算该结点的祖先结点的平衡因子,若该结点的祖先结点的平衡因子的绝对值均不超过1,则平衡二叉树没有失去平衡,继续插入结点; (2)若插入结点的某祖先结点的平衡因子的绝对值大于1,则找出其中最小不平衡子的根结点; (3)判断新插入的结点与最小不平衡子的根结点的关系,确定是哪种类型的调整; (4)如果是LL型或RR型,只需应用扁担原理旋转一次,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;如果是LR型或LR型,则需应用扁担原理旋转两次,第一次最小不平衡子的根结点先不动,调整插入结点所在子,第二次再调整最小不平衡子,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突; (5)计算调整后的平衡二叉树中各结点的平衡因子,检验是否因为旋转而破坏其他结点的平衡因子,以及调整后的平衡二叉树中是否存在平衡因子大于1的结点。 2 方案设计 2.1 模块功能 1.建立二叉树:要求以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序T。 2.中序遍历并输出结果:要求将第一步建立的二叉树进行中序遍历,并将结果输出。 3.平均查找长度并输出:要求计算二叉排序T查找成功的平均查找长度,输出结果。 4.删除节点:要求输入元素x,查找二叉排序T,若存在含x的结点,则删该结点,并作中序遍历(执行操作2);否则输出信息“无x”。 5.生成平衡二叉树:要求用数列L,生成平衡的二叉排序BT:当插入新元素之后,发现当前的二叉排序BT不是平衡的二叉排序,则立即将它转换成新的平衡的二叉排序BT; 6.平均查找长度:计算平衡的二叉排序BT的平均查找长度,输出结果。 3 算法设计 3.1 算法流程图 建立二叉树流程图: YES NO 主程序流程图: 中序遍历流程图: 删除节点流程图: 4 详细设计 4.1 主程序 void main() { node T=NULL; int num; int s=0,j=0,i=0; int ch=0; node p=NULL; printf("请输入一组数字并输入0为结束符:"); do{ scanf("%d",&num); if(!num) printf("你成功完成了输入!\n"); else insertBST(&T,num); }while(num); printf("\n\n---操作菜单---\n"); printf("\n 0: 退出" ); printf("\n 1: 中序遍历"); printf("\n 2: 平均查找长度"); printf("\n 3: 删除"); printf("\n 4: 判断是否是平衡二叉树"); while(ch==ch) { printf("\n 选择操作并继续:"); scanf("%d",&ch); switch(ch){ case 0: exit(0); /*0--退出*/ case 1: printf(" 中序遍历结果是:\n "); inorderTraverse(&T); break; case 2: s=0;j=0;i=0; calculateASL(&T,&s,&j,i); printf(" ASL=%d/%d",s,j); break; case 3: printf(" 请输入你想删除的数字:"); scanf("%d",&num); if(searchBST(T,num,NULL,&p)) { T=Delete(T,num); printf(" 你已成功删除该数字!\n "); inorderTraverse(&T); else printf(" 没有你想要删除的节点 %d!",num); break; case 4: i=0; balanceBST(T,&i); if(i==0) printf(" OK!这是平衡二叉树!"); else printf(" NO!"); break; default: printf("你的输入有误!请重新输入!\n"); break; } } } 4.2 定义二叉树结构 #include typedef struct Tnode { int data; struct Tnode *lchild,*rchild; }*node,BSTnode; 4.3 建立二叉树 4.3.1 二叉排序的查找 searchBST(node t,int key,node f,node *p){ /*在根指针t所指二叉排序中递归地查找其关键字等于key的数据元素,若查找成功,则指针p指向该数据元素节点,并返回(1),否则指针p指向查找路径上访问的最后一个节点并返回(0),指针f指向t的双亲,其初始调用值为NULL*/ if(!t) {*p=f;return (0);} /*查找不成功*/ else if(key==t->data) {*p=t;return (1);} /*查找成功*/ else if(keydata) searchBST(t->lchild,key,t,p); /*在左子中继续查找*/ else searchBST(t->rchild,key,t,p); /*在右子中继续查找*/ } 4.3.2 二叉排序的插入 insertBST(node *t,int key){ /*当二叉排序t中不存在关键字等于key的数据元素时,插入key并返回(1),否则返回(0)*/ node p=NULL,s=NULL; if(!searchBST(*t,key,NULL,&p)) /*查找不成功 */ { s=(node)malloc(sizeof(BSTnode)); s->data=key; s->lchild=s->rchild=NULL; if(!p) *t=s; /*被插入节点*s为新的根节点*/ else if(keydata) p->lchild=s; /*被插节点*s为左孩子*/ else p->rchild=s; /*被插节点*s为右孩子*/ return (1); } else return (0); /*中已有关键字相同的节点,不再插入*/ } 4.4 中序遍历 inorderTraverse(node *t) /*中序遍历*/ { if(*t){ if(inorderTraverse(&(*t)->lchild)) { printf("%d ",(*t)->data); if(inorderTraverse(&(*t)->rchild)); } } else return(1); } 4.5 平均查找长度 calculateASL(node *t,int *s,int *j,int i) /*计算平均查找长度*/ {if(*t){ i++; *s=*s+i; if(calculateASL(&(*t)->lchild,s,j,i)) { (*j)++; if(calculateASL(&(*t)->rchild,s,j,i)) {i--; return(1);} } } else return(1); } 4.6 删除节点 node Delete(node t,int key) { /*若二叉排序t中存在关键字等于key的数据元素时,则删除该数据元素节点 */ node p=t,q=NULL,s,f; while(p!=NULL) { if(p->data==key) break; q=p; if(p->data>key) p=p->lchild; else p=p->rchild; } if(p==NULL) return t; if(p->lchild==NULL) { if(q==NULL) t=p->rchild; else if(q->lchild==p) q->lchild=p->rchild; else q->rchild=p->rchild; free(p); } else{ f=p; s=p->lchild; while(s->rchild) { f=s; s=s->rchild; } if(f==p) f->lchild=s->lchild; else f->rchild=s->lchild; p->data=s->data; free (s); } return t; } 4.7 判断平衡二叉树 int balanceBST(node t,int *i) /*判断平衡二叉树*/ { int dep1,dep2; if(!t) return(0); else { dep1=balanceBST(t->lchild,i); dep2=balanceBST(t->rchild,i); } if((dep1-dep2)>1||(dep1-dep2)dep2) return(dep1+1); else return(dep2+1); } 5 调试分析 5.1 时间复杂度的分析 为了保证二叉排序的高度为lgn,从而保证然二叉排序上实现的插入、删除和查找等基本操作的时间复杂度为O(lgn)。 5.2 运行结果 图5.1.1 调试界面 在程序调试过程当中,编译时并没有报错,但是运行时总是出错,在查阅资料和同学的帮助下,发现程序未对数组初始化。添加数组初始化代码: s=(node)malloc(sizeof(BSTnode)) 输入一组数列,以结0结束: 图5.2.2运行界面一 中序遍历: 图5.2.3运行界面二 计算平均查找长度 图5.2.4运行界面三 删除已有结点: 图5.2.5运行界面四 删除失败: 图5.2.6运行界面五 判断是否是平衡二叉树: 图5.2.7运行界面六 5.3 结果分析 通过运行程序和严密的求证,运行结果无误,不过对于转换平衡二叉树平衡二叉树平均查找长度未能实现,同时也无法实现图像显示。 6 课程设计总结 在这一周的课程设计中,其实对我来说还是收获颇多。这不光提高了我的程序设计能力,更为我的就业增加了筹码。对我们来说,独立完成这样课程设计是比较困难,其中包括模块的组成分析和模块功能的实现。最后我不得不从网上下载源程序,借助课本,困难地将几个模块串起来。最后终于完成了自己的课程设计。 这次实验中我也出现过一些比较严重的错误。在用一维数组顺序表结构编写程序时我错误的运用静态链表来实现函数功能。这是我对基本概念理解的模糊不清造成的。我原以为只要采用一维数组作为存储结构它就一定也是顺序表结构,而实质上这根本是两个不相干的概念。后来在同学的指点下我意识到自己的错误。不过收获也很不少。至少我又练习了运用静态链表来实现同样的功能,同时我也发现两者在很多函数上是互通的,只需稍作修改即可移植。 另外程序的不足之处是不能实现对0这个数字的存储,可以通过改变数字的存储结构方式来实现,如使用二叉链表来作为数据的存储结构,即可实现该功能。还有就是可能自己学的还不够,对于最后两个要求未能完成,不得不说这是自己学艺不精。 现在觉得以前我对数据结构的认识是那么的肤浅,因此我下定决心寒假一定好好的把数据结构复习一遍。而且本次课程设计不光增强了我程序调试的能力,还有在面对一个较大的程序要冷静,不要浮躁,先分析模块要实现的功能,再把模块划分,最后到一个一个得模块实现,并且要不断地练习,这样,一个大的程序对我来说将不成问题。 参考文献 [1]刘大有等,《数据结构》(C语言版),高等教育出版社 [2]严蔚敏等,《数据结构》(C语言版),清华大学出版社 [3]William Ford,William Topp,《Data Structure with C++》清华大学出版社 [4]苏仕华等,数据结构课程设计,机械工业出版社
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值