快速理解平衡二叉树、B-tree、B+tree、B*tree

原文:https://my.oschina.net/u/3370829/blog/1301732

满二叉树


除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。或者说:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。或者说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。

 

完全二叉树

 

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
或者说:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

性质:
假设n0是度为0的结点总数(即叶子结点数),n1是度为1的结点总数,n2是度为2的结点总数,则 :

  • n= n0+n1+n2 (其中n为完全二叉树的结点总数);又因为一个度为2的结点会有2个子结点,一个度为1的结点会有1个子结点,除根结点外其他结点都有父结点,
  • n= 1+n1+2*n2 ;由①、②两式把n2消去得:n= 2*n0+n1-1,由于完全二叉树中度为1的结点数只有两种可能0或1,由此得到n0=n/2 或 n0=(n+1)/2。

简便来算,就是 n0=n/2,其中n为奇数时(n1=0)向上取整;n为偶数时(n1=1)。可根据完全二叉树的结点总数计算出叶子结点数。

二叉排序树(二叉搜索树/二叉查找树)

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均<=它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均>=它的根结点的值;
(3)左、右子树也分别为二叉排序树;

 

平衡二叉树

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

性质:

  • 解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多
  • 平衡二叉树大部分操作和二叉查找树类似,主要不同在于插入删除的时候平衡二叉树的平衡可能被改变,并且只有从那些插入点到根结点的路径上的结点的平衡性可能被改变,因为只有这些结点的子树可能变化。

 

平衡树的层级结构:

因为平衡二叉树查询性能和树的层级(h高度)成正比、为了保证树的结构左右两端数据大致平衡降低二叉树的查询难度一般会采用一种算法机制实现节点数据结构的平衡,实现了这种算法的有比如AVL、Treap、红黑树,使用平衡二叉树能保证数据的左右两边的节点层级相差不会大于1.,通过这样避免树形结构由于删除增加变成线性链表影响查询效率

二叉树的优点与对比

二叉树的优点

  二叉排序树是一种比较有用的折衷方案:  

  •   数组的搜索比较方便,可以直接用下标,但删除或者插入某些元素就比较麻烦。  
  •   链表与之相反,删除和插入元素很快,但查找很慢。  
  •   二叉排序树就既有链表的好处,也有数组的好处。  
  •   在处理大批量的动态的数据是比较有用。
  • 文件系统和数据库系统一般都采用树(特别是B树)的数据结构数据:主要为排序和检索的效率。
  • 二叉树是一种最基本最典型的排序树,本身很少在实际中进行应用,因为缺点太明显了。

对比普通二叉树和平衡二叉树

二叉树支持动态的插入和查找,保证操作在O(height)时间,这就是完成了哈希表不便完成的工作,动态性。但是二叉树有可能出现worst-case,如果输入序列已经排序,则时间复杂度为O(N)

平衡二叉树/红黑树就是为了将查找的时间复杂度保证在O(logN)范围内。
所以如果输入结合确定,所需要的就是查询,则可以考虑使用哈希表,如果输入集合不确定,则考虑使用平衡二叉树/红黑树,保证达到最大效率

平衡二叉树主要优点集中在快速查找。
如果你知道SGI/STL的set/map底层都是用红黑树(平衡二叉树的一种)实现的,相信你会对这些树大有兴趣。

 

B树 (B-tree)


注意:之前有看到有很多文章把B树和B-tree理解成了两种不同类别的树,其实这两个是同一种树;

1、m阶B树定义

m阶B树是一棵平衡的m路搜索树,或者是空树,或者是满足以下条件:

1. 除了叶子结点,节点含有关键字记录孩子指针关键字个数 = 孩子个数 - 1

2. 树中的每个节点最多有m个孩子 

3. 如果根节点不是叶子结点,根节点孩子数:

            2 <= n_root <= m 

4. 除了根节点和叶子结点外,其他节点的孩子数目 n_ch:

            (m+1)/2 <= n_ch <= m 

            ( ceil(m/2) 即是 (m+1)/2,向上取整)

5. 所有叶子节点都在同一层,并不带任何信息

m阶B树的非叶子结点

  • 关键字:K[1], K[2], …, K[M-1],且K[i] < K[i+1],即关键字时有序的,按从左到右递增次序排列。
  • 孩子指针:P[1], P[2], …, P[M]
  • P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于**(K[i-1], K[i])**的子树。
  • 时间复杂度:O(nlogn)。

m = 3 的B树:

特点

  • B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点存储关键字数据的地址,所以这种数据检索的时候会要比B+树快。
  •  所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;

B树对比平衡二叉树

B树的每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个块的大小一般为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制和充分使用在磁盘快大小范围;

把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度;

 

B+树

B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+树查找的效率要比B树更高、更稳定;

B-树和B+树的区别

(1)B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,这样使得B+树每个节点所能保存的关键字大大增加

(2)B+树叶子节点保存了父节点的所有关键字和关键字记录的指针每个叶子节点的关键字从小到大链接

(3)B+树的非叶子结点的子树指针与关键字个数相同

(4)B+的非叶子节点只进行数据索引,不会存实际的关键字记录的指针,所有数据地址必须要到叶子节点才能获取到每次数据查询的次数都一样

优点

  1. B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
  2. B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
  3. B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
  4. B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
  5. 能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度

适应场景

通常用于数据库和操作系统的文件系统中。

在B树的基础上每个节点存储的关键字数更多,树的层级更少所以查询数据更快,所有指关键字指针都存在叶子节点,所以每次查找的次数都相同所以查询速度更稳定;

结点的分裂

  • 将已满结点进行分裂,将已满节点后M/2节点生成一个新节点,将新节点的第一个元素指向父节点。
  • 父节点出现已满,将父节点继续分裂。
  • 一直分裂,如果根节点已满,则需要分类根节点,此时树的高度增加。

 

B*树

B*树是B+树的变种

对比:

(1)首先是关键字个数限制问题,B+树初始化的关键字初始化个数是cei(m/2),b*树的初始化个数为(cei(2/3*m))

(2)B+树节点满时就会分裂,而B*树节点满时会检查兄弟节点是否满(因为每个节点都有指向兄弟的指针),如果兄弟节点未满则向兄弟节点转移关键字,如果兄弟节点已满,则从当前节点和兄弟节点各拿出1/3的数据创建一个新的节点出来;

特点:

在B+树的基础上因其初始化的容量变大,使得节点空间使用率更高,而又存有兄弟节点的指针,可以向兄弟节点转移关键字的特性使得B*树额分解次数变得更少;

 

总结

  • 从平衡二叉树、B树、B+树、B*树总体来看它们的贯彻的思想是相同的,都是采用二分法和数据平衡策略来提升查找数据的速度;
  • 不同点是他们一个一个在演变的过程中通过IO从磁盘读取数据的原理进行一步步的演变,每一次演变都是为了让节点的空间更合理的运用起来,从而使树的层级减少达到快速查找数据的目的;
  • 二叉搜索树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于

    走右结点;

    B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键

    字范围的子结点;

               所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;

     B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点

    中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;

     B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率

    从1/2提高到2/3;

如果还没理解的话推荐以下资料描叙的很详细:

推荐资料:

附一(二分法查找):https://zhuanlan.zhihu.com/p/27597160

附二(B、B+、B*树):http://blog.csdn.net/v_JULY_v/article/details/6530142/

附三(B、B+、B*树):http://blog.csdn.net/endlu/article/details/51720299

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值