查找算法之B树、B+树

B树是为了磁盘或其他存储设备而设计的一种多叉平衡查找树.磁盘中有两个机械运动的部分,分别是盘片旋转和磁臂移动。盘片旋转就是我们市面上所提的多少转每分钟,而磁盘移动则是在盘片旋转到指定位置以后,移动磁臂后开始进行数据的读写,那么这就存在一个定位到磁盘中的块的过程,而定位是磁盘的存取中花费的时间比较大的一块,毕竟机械运动花费的时间要远远大于电子于东的时间。当大规模数据存储到磁盘中的时候,显然定位是一个非常花费时间的过程,但是我们可以通过B树进行优化,提高磁盘读取时定位的效率。
为什么B类树可以进行优化呢?我们可以根据B类树的特点,构造一个多阶B类树,然后在尽量多的节点上存储相关的信息,保证层数尽可能的少,以便后面我们可以更快的找到信息,磁盘的I/0操作也少一些。树的高度是和IO次数相关的。

B树

B树又叫平衡多路查找树一棵m阶的B树的特征如下:
1、树的每个节点最多含有m个孩子(m>=2)
2、除根节点和叶子节点外,其他每个节点至少有ceil[m/2]个孩子(ceil取上限)
3、若根节点不是叶子节点,则至少有2个孩子
4、所有的叶子节点都出现在同一层,叶子节点不包含任何关键字信息(可以看做是外部节点或查询失败的节点,实际上这些节点不存在,指向这些节点的指针都为null)
5、每个非终端节点中包含有n个关键字信息(P1,K1,P2,K2,P3,……Kn,Pn+1).其中:
a)、ki为关键字,且关键字按顺序升序排序
b)、pi为指向子树的根节点,且指针p(i)指向子树中所有节点的关键字均小于ki,但都大于K(i-1)
c)、关键字的个数n必须满足:[ceil(m/2)-1]<=n<=m-1
《查找算法之B树、B+树》

查找

模拟查找文件29的过程
(1) 根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘IO操作1次】

(2) 此时内存中有两个文件名17,35和三个存储其他磁盘页面地址的数据。根据算法我们发现17<29<35,因此我们找到指针p2。

(3) 根据p2指针,我们定位到磁盘块3,并将其中的信息导入内存。【磁盘IO操作2次】

(4) 此时内存中有两个文件名26,30和三个存储其他磁盘页面地址的数据。根据算法我们发现26<29<30,因此我们找到指针p2。

(5) 根据p2指针,我们定位到磁盘块8,并将其中的信息导入内存。【磁盘IO操作3次】

(6) 此时内存中有两个文件名28,29。根据算法我们查找到文件29,并定位了该文件内存的磁盘地址。

插入

生成从空树开始,逐个插入关键字。但是由于B_树节点关键字必须大于等于[ceil(m/2)-1],所以每次插入一个关键字不是在树中添加一个叶子结点, 而是首先在最底层的某个非终端节点中添加一个“关键字”,该结点的关键字不超过m-1,则插入完成;否则要产生结点的“分裂”,将一半数量的关键字元素分裂到新的其相邻右结点中,中间关键字元素上移到父结点中。

1、咱们通过一个实例来逐步讲解下。插入以下字符字母到一棵空的B 树中(非根结点关键字数小了(小于2个)就合并,大了(超过4个)就分裂):C N G A H E K Q M F W L T Z D P R X Y S,首先,结点空间足够,4个字母插入相同的结点中,如下图:
《查找算法之B树、B+树》
2、当咱们试着插入H时,结点发现空间不够,以致将其分裂成2个结点,移动中间元素G上移到新的根结点中,在实现过程中,咱们把A和C留在当前结点中,而H和N放置新的其右邻居结点中。如下图:
《查找算法之B树、B+树》

3、当咱们插入E,K,Q时,不需要任何分裂操作
《查找算法之B树、B+树》

4、插入M需要一次分裂,注意M恰好是中间关键字元素,以致向上移到父节点中

《查找算法之B树、B+树》

5、插入F,W,L,T不需要任何分裂操作
《查找算法之B树、B+树》

6、插入Z时,最右的叶子结点空间满了,需要进行分裂操作,中间元素T上移到父节点中,注意通过上移中间元素,树最终还是保持平衡,分裂结果的结点存在2个关键字元素。
《查找算法之B树、B+树》

7、插入D时,导致最左边的叶子结点被分裂,D恰好也是中间元素,上移到父节点中,然后字母P,R,X,Y陆续插入不需要任何分裂操作(别忘了,树中至多5个孩子)。
《查找算法之B树、B+树》

8、最后,当插入S时,含有N,P,Q,R的结点需要分裂,把中间元素Q上移到父节点中,但是情况来了,父节点中空间已经满了,所以也要进行分裂,将父节点中的中间元素M上移到新形成的根结点中,注意以前在父节点中的第三个指针在修改后包括D和G节点中。这样具体插入操作的完成。
《查找算法之B树、B+树》

B+树

一棵m阶的B+树和m阶的b数的差异在于:
1、有n棵子树的节点中含有n个关键字;(B树是n棵子树中有n-1个关键字)
2、所有叶子节点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大的顺序链接(而B树的叶子节点并没有包括全部需要查找的信息)
3、所有的非终端节点可以看成是索引部分,节点中仅含有其子树根节点中最大(最小)的关键字。而B树的非终结点也需要包含需要查找的有效信息。
《查找算法之B树、B+树》

###为什么说B+tree比B 树更适合实际应用中操作系统的文件索引和数据库索引?
B+tree的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+ 树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B 树就比B+ 树多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。

2) B+tree的查询效率更加稳定

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

数据库索引采用B+树的主要原因是 B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低)。

转载自:https://blog.csdn.net/endlu/article/details/51720299

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