B树与B+树

二叉搜索树、平衡二叉树、红黑树都属于二叉树,由于每个节点只有一个元素,每个节点只能连接两个节点。对于像文件系统、数据库这样需要数目庞大读写删除操作,如果采用这种数据结构将会大大降低系统的效率,遇到I/O读写的瓶颈。

有没有一种数据结构可以降低往返于节点之间的次数呢?答案是有的,就是B树。什么是叫B树呢?和二叉树有啥区别呢?

了然于心二叉树的劣势,这个B树每个节点必然不是只是含有一个节点了,可以进行多路查找,B树是一种平衡的多路查找树。下图就是一颗B树

《B树与B+树》

一个m阶的B树,满足以下性质:

1、非叶子节点至少有两个子树,最多m个子树;

2、非根的分支节点,有k-1个键值,有k个子树,并且按照升序进行排列。每一个叶子节点均含有k-1个元素。这里的([m/2]<k<=m),这里的m/2需要向上取整;

3、所有的叶子节点位于同一层次;

4、每一个节点含有键值、指向子树指针等相关的信息。

提到B树,既然是一颗树,就对树的元素的插入与删除比较感兴趣。

插入过程:

首先是在恰当的叶子结点中添加关键码,如果该结点中关键码不超过m-1个,则插入成功。

否则要把这个结点分裂为两个。并把中间的一个关键码拿出来插到结点的父结点里去。父结点也可能是满的,就需要再分裂,再往上插。

最坏的情况,这个过程可能一直传到根,如果需要分裂根,由于根是没有父结点的,这时就建立一个新的根结点。

插入可能导致B树朝着根的方向生长。

下面以一棵阶数为3的B树为例,说说B树的插入与删除的过程,此过程中每次的插入或者删除都要调整B树使得满足B树的几个条件。

《B树与B+树》

《B树与B+树》

《B树与B+树》

节点的删除过程(红色标记的为待删除的节点)如下:

《B树与B+树》

以上为3阶B树的插入删除过程的一个例子,可以在此基础上进行体会。在实际的生产中一般B树的阶数很大,具体的删除规则与此类似。

B树使用最多的场景是文件系统与数据库,必然涉及到查找。那么一个含有n个元素,m阶的B树的最大深度是多少?

第一层含有1个节点;

第二层至少有两个节点,由于分支节点至少含有[m/2]个节点。

第三层至少有2*[m/2]个节点;

第四层至少有2*[m/2]*[m/2];

以此类推。。。

第k层至少有《B树与B+树》个节点;

则叶子层k+1层有《B树与B+树》个节点。

查找不成功的次数为n+1。则有如下结果:

《B树与B+树》

所以含有n个关键元素的m阶B树的深度最大为:

《B树与B+树》

下面看B树的另一种方式B+树。

首先看下B+树的形式:

《B树与B+树》

观察此树每个节点的内容可以看出,子节点包含父节点的所有关键字。所以所有的叶子节点包含全部的关键字信息。

所以B+树相对于B树的变化的情况是:

有n棵子树的节点含有n个关键字;

所有的叶子节点含有所有的关键字,以及指向包含这些关键字记录的指针,叶子节点本身的关键字自小到大依次排列;

所有分支节点都看成是索引,节点中仅仅含有其子树中最大或者最小的关键字。

看了B树与B+树的不同,在进行查找的时候,利用B树需要频繁地往返于每个节点之间,这就意味着,我们必须经过多次的访问才能得到结果,每次遍历的时候可能要频繁经过某个节点,这降低了查找的性能。而B+可以解决重复访问节点的问题。

B+树查找的时候,如果从根节点开始遍历查找关键字,在节点处查找到结果,这个也只是用以索引,不是真实的访问记录,还是要遍历到叶子节点才结束;若从小到大查找,只需要从叶子节点的最左端开始,顺序遍历就可以得到。

B+树的一缺点:B+树最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在物理上往往不连续,甚至分离的很远,但做范围查询时,会产生大量读随机IO。解决B+树这一问题可采用LSM树,即Log-Structured Merge-Trees。其中Hbase中就利用LSM,感兴趣可以多查查LSM树相关的知识,这里就不再赘述。

    原文作者:B树
    原文地址: https://blog.csdn.net/xygl2009/article/details/46817281
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞