多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树

多路查找树

每一个结点的孩子数可以多于两个,且每一个结点处可以存储多个元素。由于它是查找树,所有元素之间存在某种特定的排序关系。

四种特殊形式:2-3树、2-3-4树、B树和B+树

2-3树

概念:
1、2-3树是这样的一棵多路查找树:其中的每一个结点都具有两个孩子(我们称它为2结点)或三个孩子(我们称它为3结点)。

2、一个2结点包含一个元素和两个孩子(或没有孩子),且与二叉排序树类似,左子树包含的元素小于该元素,右子树包含的元素大于该元素。不过,与二叉排序树不同的是,这个2结点要么没有孩子,要有就有两个,不能只有一个孩子。

3、一个3结点包含一小一大两个元素和三个孩子(或没有孩子),一个3结点要么没有孩子,要么具有3个孩子。如果某个3结点有孩子的话,左子树包含小于较小元素的元素,右子树包含大于较大元素的元素,中间子树包含介于两元素之间的元素。

4、并且2-3树中所有的叶子都在同一层次上。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

注意: 2-3树复杂的地方在于新结点的插入和已有结点的删除。每个结点可能是2结点也可能是3结点,要保证所有叶子结点在同一层次。

2-3树的插入

对于2-3树的插入来说,与二叉排序树相同,插入操作一定是发生在叶子结点上。可与二叉排序树不同的是,2-3树插入一个元素的过程有可能对该树的其余结构造成连锁反应。

2-3树的插入分三种情况:
1、对于空树,插入一个2结点即可。
2、插入结点到一个2结点的叶子上,由于其本身就只有一个## 标题 ##元素,所以只需要将其升级为3结点即可。
3、要往3结点中插入一个新元素,因为3结点本身已经是2-3树的结点最大容量,已经有两个元素,因此就需要将其拆分,且将树中两元素或插入元素的三者中选择其一向上移动一层。这里又分为三种情况:
(1)
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
(2)
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
(3)
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
结论: 如果2-3树的插入的传播效应导致了根结点的拆分,则树的高度就会增加。

2-3树的删除

分三种情况:

1、所删除元素位于一个3结点的叶子结点上,只需要在该结点处删除该元素即可,不会影响到整棵树的其他结点结构。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
2、所删除的元素位于一个2结点上,即要删除的是一个只有一个元素的结点。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
1)此结点的双亲是2结点,且拥有一个3结点的右孩子。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
2)此结点的双亲是2结点,它的右孩子也是2结点。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
3)此结点的双亲是一个3结点。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
4)如果当前树是一个满二叉树的情况。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
3、所删除的元素位于非叶子的分支结点。
1)
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
2)
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

2-3-4树

2-3-4树是2-3树的概念扩展,包括了4结点的使用。一个4结点包含小中大三个元素和四个孩子(或没有孩子),一个4结点要么没有孩子,要么具有4个孩子。如果某个4结点右孩子的话,左子树包含小于最小元素的元素;第二个子树包含大于最小元素,小于第二元素的元素;第三字数包含书大于第二元素,小于最大元素的元素;右子树包含大于最大元素的元素。

构建一个数组为{7,1,2,5,6,9,8,4,3}的2-3-4树的过程:

2-3-4树的插入:
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
2-3-4树的删除:
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

B树

B树是一种平衡的多路查找树,2-3树和2-3-4树都是B树的特例。结点最大的孩子数目称为B树的阶,因此2-3树是3阶B树,2-3-4树是4阶B树。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
在B树上查找的过程是一个顺时针查找结点和在结点中查找关键字的交叉过程。

比方说,我们要查找数字7,首先从外存(比如硬盘中)读取得到根结点3 、5 、8三个元素,发现7不在当中,但在5和8之间,因此就通过A2再读取外存的6 、7结点,查找到所耍的元素。

至于B树的插入和删除,方式是与2-3树2-3-4树相类似的,只不过阶数可能会很大而已。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
B树的插入
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
B树的删除
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

B+树

对于树结构来说,我们都可以通过中序遍历来顺序查找树中的元素,这一切都是在内存中进行。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

B树和B+树的区别

《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
如果要随机查找,我们就从根结点出发,与B树的查找的方式不同,只不过即使在分支结点找到了待查找的关键字,它也只是用来索引的,不能提供实际记录的访问,还是需要到达包含此关键字的终端结点。

如果我们是需要从最小关键字进行从小到大的顺序查找,我们就可以从最左侧的叶子结点出发,不经过分支结点,而是延着指向下一叶子的指针就可遍历所有的关键字。
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
B/B+树通过对每个节点存储个数的扩展,使得对连续的数据能够进行较快的定位和访问,能够有效减少查找时间,提高存储的空间局部性从而减少IO操作。他广泛用于文件系统及数据库中,如:

Windows:HPFS文件系统
Mac:HFS,HFS+文件系统
Linux:ResiserFS,XFS,Ext3FS,JFS文件系统
数据库:ORACLE,MYSQL,SQLSERVER等中

根据B+树的结构,我们可以发现B+树相比于B树,在文件系统,数据库系统当中,更有优势,原因如下:

1、B+树的磁盘读写代价更低
B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说I/O读写次数也就降低了。
举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+ 树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B 树就比B+ 树多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。

2、B+树的查询效率更加稳定
由于内部结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

2、B+树更有利于对数据库的扫描
B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题,而B+树只需要遍历叶子节点就可以解决对全部关键字信息的扫描,所以对于数据库中频繁使用的range query,B+树有着更高的性能。

B*树

B*-tree是B+-tree的变体,在B+树的基础上(所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针),B*树中非根和非叶子结点再增加指向兄弟的指针;B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2)。给出了一个简单实例,如下图所示:
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。

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

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

总结:
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》
B树是一棵平衡树,它是把一维直线分为若干段线段,当我们查找满足某个要求的点的时候,只要去查找它所属的线段即可。依我看来,这种思想其实就是先找一个大的空间,再逐步缩小所要查找的空间,最终在一个自己设定的最小不可分空间内找出满足要求的解。一个典型的B树查找如下:
《多路查找树:2-3树、2-3-4树、B树、B+树、B*树、R树》

R树

R树在数据库等领域做出的功绩是非常显著的。它很好的解决了在高维空间搜索等问题。举个R树在现实领域中能够解决的例子:查找20英里以内所有的餐厅。如果没有R树你会怎么解决?一般情况下我们会把餐厅的坐标(x,y)分为两个字段存放在数据库中,一个字段记录经度,另一个字段记录纬度。这样的话我们就需要遍历所有的餐厅获取其位置信息,然后计算是否满足要求。如果一个地区有100家餐厅的话,我们就要进行100次位置计算操作了,如果应用到谷歌地图这种超大数据库中,这种方法便必定不可行了。

R树就很好的解决了这种高维空间搜索问题。它把B树的思想很好的扩展到了多维空间,采用了B树分割空间的思想,并在添加、删除操作时采用合并、分解结点的方法,保证树的平衡性。因此,R树就是一棵用来存储高维数据的平衡树。

参考:
《大话数据结构》
https://www.cnblogs.com/George1994/p/7008732.html
https://blog.csdn.net/v_july_v/article/details/6530142
https://www.cnblogs.com/vincently/p/4526560.html
http://blog.codinglabs.org/articles/theory-of-mysql-index.html

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