数据结构:B树&B+树&B*树

本系列博客整理自网络,其中加入部分个人见解,如果你在看到这个系列的博客的时候有似曾相识的感觉,非常正常,主要是用于本人以后学习与复习,参考的原博客的地址我也会在博客前面或后面给出。

一、B树

        B 树又叫平衡多路查找树。一棵m阶的B 树的特性如下:

(1)树中的每个节点最多拥有m个子节点且m>=2,空树除外(注:m阶代表一个树节点最多有多少个查找路径,m阶=m路,当 m=2则是2叉树,m=3则是3叉);

(2)除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数);

(3)所有叶子节点均在同一层、叶子节点除了包含了关键字信息。(结合知乎的那篇和July的博客,我的理解是最后一层的叶 子结点其实是可以不存在的,参见红黑树的那些黑色的叶子结点,即为NULL。知乎的那篇文章更好理解一些,但是还是 那个意思,也就是指向子树的指针全部都是NULL。图我截下来放在下面,如果不理解可以进入知乎那篇文章,文章地址 在前面!)

(4)若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节 点);

(5)每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,……,Kn,Pn)。其中:

       a)  Ki (i=1…n)为关键字,且关键字按顺序升序排序K(i-1)< Ki。

       b)  Pi为指向子树根的接点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。(其实Pi就是一个指 针,指向子树。)

       c)  关键字的个数n必须满足: [ceil(m / 2)-1]<= n <= m-1。

最后我们用一个图和一个实际的例子来理解B树(这里为了理解方便我就直接用实际字母的大小来排列C>B>A)。

《数据结构:B树&B+树&B*树》

 

B树的查询流程:(如上图我要从上图中找到E字母,查找流程如下)

(1)获取根节点的关键字进行比较,当前根节点关键字为M,E要小于M(26个字母顺序),所以往找到指向左边的子节点 (二分法规则,左小右大,左边放小于当前节点值的子节点、右边放大于当前节点值的子节点);

(2)拿到关键字D和G,D<E<G 所以直接找到D和G中间的节点;

(3)拿到E和F,因为E=E 所以直接返回关键字和指针信息(如果树结构里面没有包含所要查找的节点则返回null);

 

树的高度

根据上面的例子我们可以看出,对于辅存做IO读的次数取决于B树的高度。而B树的高度由什么决定的呢?

若B树某一非叶子节点包含N个关键字,则此非叶子节点含有N+1个孩子结点,而所有的叶子结点都在第I层,我们可以得出:

(1)因为根至少有两个孩子,因此第2层至少有两个结点。

(2)除根和叶子外,其它结点至少有┌m/2┐个孩子,

(3)因此在第3层至少有2*┌m/2┐个结点,

(4)在第4层至少有2*(┌m/2┐^2)个结点,

(5)在第 I 层至少有2*(┌m/2┐^(l-2) )个结点,于是有: N+1 ≥ 2*┌m/2┐I-2;

(6)考虑第L层的结点个数为N+1,那么2*(┌m/2┐^(l-2))≤N+1,也就是L层的最少结点数刚好达到N+1个,即: I≤log┌m/2┐((N+1)/2 )+2;

(7)所以,当B树包含N个关键字时,B树的最大高度为l-1(因为计算B树高度时,叶结点所在层不计算在内),即:l – 1 = log┌m/2┐((N+1)/2 )+1。

 

B树的插入节点流程

定义一个5阶树(平衡5路查找树;),现在我们要把3、8、31、11、23、29、50、28 这些数字构建出一个5阶树出来;遵循规则:

(1)当前是要组成一个5路查找树,那么此时m=5,关键字数必须大于等于cei(5/2)-1小于等于5-1(关键字数小于cei(5/2)-1 就要 进行节点合并,大于5-1就要进行节点拆分);

(2)满足左大右小的排序规则;

《数据结构:B树&B+树&B*树》《数据结构:B树&B+树&B*树》《数据结构:B树&B+树&B*树》

下面这个博客有个生成的动态图,可以帮你更好的理解!

 

http://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html

 

B树节点的删除

规则:

(1)当前是要组成一个5路查找树,那么此时m=5,关键字数必须大于等于cei(5/2)-1小于等于5-1;

(2)满足左大右小的排序规则;

(3)关键字数小于二时先从子节点取,子节点没有符合条件时就向向父节点取,取中间值往父节点放;

《数据结构:B树&B+树&B*树》

 

 

 

B+树

B+-tree:是应文件系统所需而产生的一种B-tree的变形树。

一棵m阶的B+树和m阶的B树的异同点在于:

      1.有n棵子树的结点中含有n个关键字;

       2.所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息)

      3.所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含  需要查找的有效信息)

 

下面这个链接说明了B树和B+树的不同之处,后面有最高票答案的翻译。

https://stackoverflow.com/questions/870218/differences-between-b-trees-and-b-trees

 《数据结构:B树&B+树&B*树》

 

B+ 树的优点在于: 

       由于B+树在内部节点上不好含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子几点上关联的数据也具有更好的缓存命中率。

       B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。

       但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。下面是B 树和B+树的区别图:

《数据结构:B树&B+树&B*树》

B*树

         B*-tree是B+-tree的变体,在B+树的基础上(所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针),B*树中非根和非叶子结点再增加指向兄弟的指针;B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2)。给出了一个简单实例,如下图所示:

 

《数据结构:B树&B+树&B*树》

 

B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。

B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。

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

 

参考博客:

 

http://blog.csdn.net/v_JULY_v/article/details/6530142/

https://zhuanlan.zhihu.com/p/27700617

http://blog.jobbole.com/107800/

 

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