B-树详解(二)

引言

B-树详解(一)的部分,我们从数据库索引出发,比较了二叉查找树和B-Tree的查找效率,B-Tree通过减少磁盘IO提高查找效率。在第一部分我们对B-树的定义和整体有了一定的认识,下面就重点看看B-Tree查找,插入,和删除的具体过程。

定义

B树是一种平衡的多分树,通常我们说m阶的B树,它或者是空树,或者必须满足如下条件:

  • 如果根不是叶节点,则根至少有两个子节点(不然的话就成单支了),有[1,m-1]个元素
  • 每个中间节点(不是根节点和叶子节点)都包含[math.ceil(m/2)-1,m-1]个元素和[math.ceil(m/2),m]个子节点
  • 每一个叶子节点都包含[math.ceil(m/2)-1,m-1]个元素
  • 每个节点最多只有m个子节点。
  • 所有叶子节点都位于同一层(高度一致)。
  • 每个节点中的元素从小到大排列,节点当中第k-1个元素正好是第k个孩子包含的元素的值域分划。

注:
math.ceil(x)是返回数字的上入整数。例如 math.ceil(1.2)返回2。

查找

以简单的3阶B-tree为例,查询数值为5
在这里插入图片描述
第一次磁盘IO:
在这里插入图片描述
第一次在内存中定位(和9比较):
在这里插入图片描述
第二次磁盘IO:

第二次在内存中定位(和2,6比较):
在这里插入图片描述
第三次磁盘IO:
在这里插入图片描述
第三次在内存中定位(和3,5比较):
在这里插入图片描述
总结:

  • B-Tree在查找过程中的比较次数并不比二叉查找树少,尤其当单一节点的元素很多时,B-Tree的比较次数可能较多(但从第一节中我们可以得知"执行一次IO的时间可以执行40万条指令",所以比较次数的略微增加并没有任何影响)
  • B-Tree在查找过程的磁盘IO数目减少(由4次降低到3次,可相当于快了9MS),这就是B-tree的优势之一,另一大优势就是自平衡

补充:

  • B-Tree在节点内部查找采用二分查找,后面要讲的B+树也是

插入

针对m阶高度h的B树,插入一个元素时,首先在B树中是否存在,如果不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素。

  • 若该节点元素个数小于m-1,直接插入;
  • 若该节点元素个数等于m-1,引起节点分裂;以该节点中间元素为分界,取中间元素(偶数个数,中间两个随机选取)插入到父节点中;
  • 重复上面动作,直到所有节点符合B树的规则;最坏的情况一直分裂到根节点,生成新的根节点,高度增加1;

以5阶B-树为例:

5阶B树关键点:

  • 2<=根节点子节点个数<=5
  • 3<=内节点子节点个数<=5
  • 1<=根节点元素个数<=4
  • 2<=非根节点元素个数<=4

在这里插入图片描述
图(1)插入元素【8】后变为图(2),此时根节点元素个数为5,不符合 1<=根节点元素个数<=4,进行分裂(真实情况是先分裂,然后插入元素,这里是为了直观而先插入元素,下面的操作都一样,不再赘述),取节点中间元素【7】,加入到父节点,左右分裂为2个节点,如图(3)
在这里插入图片描述
接着插入元素【5】,【11】,【17】时,不需要任何分裂操作,如图(4)

在这里插入图片描述
插入元素【13】
在这里插入图片描述
节点元素超出最大数量,进行分裂,提取中间元素【13】,插入到父节点当中,如图(6)
在这里插入图片描述
接着插入元素【6】,【12】,【20】,【23】时,不需要任何分裂操作,如图(7)
在这里插入图片描述
插入【26】时,最右的叶子结点空间满了,需要进行分裂操作,中间元素【20】上移到父节点中,注意通过上移中间元素,树最终还是保持平衡,分裂结果的结点存在2个关键字元素。
在这里插入图片描述
插入【4】时,导致最左边的叶子结点被分裂,【4】恰好也是中间元素,上移到父节点中,然后元素【16】,【18】,【24】,【25】陆续插入不需要任何分裂操作
在这里插入图片描述
最后,当插入【19】时,含有【14】,【16】,【17】,【18】的结点需要分裂,把中间元素【17】上移到父节点中,但是情况来了,父节点中空间已经满了,所以也要进行分裂,将父节点中的中间元素【13】上移到新形成的根结点中,这样具体插入操作的完成。
在这里插入图片描述

删除

首先查找B树中需删除的元素,如果该元素在B树中存在,则将该元素在其结点中进行删除;删除该元素后,首先判断该元素是否有左右孩子结点,如果有,则上移孩子结点中的某相近元素(“左孩子最右边的节点”或“右孩子最左边的节点”)到父节点中,然后是移动之后的情况;如果没有,直接删除。

  • 某结点中元素数目小于(m/2)-1,(m/2)向上取整,则需要看其某相邻兄弟结点是否丰满;
  • 如果丰满(结点中元素个数大于(m/2)-1),则向父节点借一个元素来满足条件;
  • 如果其相邻兄弟都不丰满,即其结点数目等于(m/2)-1,则该结点与其相邻的某一兄弟结点进行“合并”成一个结点;

接下来还以5阶B树为例,详细讲解删除的动作;

  • 关键要领,元素个数小于 2(m/2 -1)就合并,大于4(m-1)就分裂

如图依次删除依次删除【8】,【20】,【18】,【5】
在这里插入图片描述
首先删除元素【8】,当然首先查找【8】,【8】在一个叶子结点中,删除后该叶子结点元素个数为2,符合B树规则,操作很简单,咱们只需要移动【11】至原来【8】的位置,移动【12】至【11】的位置(也就是结点中删除元素后面的元素向前移动)
在这里插入图片描述
下一步,删除【20】,因为【20】没有在叶子结点中,而是在中间结点中找到,咱们发现他的继承者【23】(字母升序的下个元素),将【23】上移到【20】的位置,然后将孩子结点中的【23】进行删除,这里恰好删除后,该孩子结点中元素个数大于2,无需进行合并操作。
在这里插入图片描述
下一步删除【18】,【18】在叶子结点中,但是该结点中元素数目为2,删除导致只有1个元素,已经小于最小元素数目2,而由前面我们已经知道:如果其某个相邻兄弟结点中比较丰满(元素个数大于ceil(5/2)-1=2),则可以向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中,在这个实例中,右相邻兄弟结点中比较丰满(3个元素大于2),所以先向父节点借一个元素【23】下移到该叶子结点中,代替原来【19】的位置,【19】前移;然【24】在相邻右兄弟结点中上移到父结点中,最后在相邻右兄弟结点中删除【24】,后面元素前移。
在这里插入图片描述
最后一步删除【5】, 删除后会导致很多问题,因为【5】所在的结点数目刚好达标,刚好满足最小元素个数(ceil(5/2)-1=2),而相邻的兄弟结点也是同样的情况,删除一个元素都不能满足条件,所以需要该节点与某相邻兄弟结点进行合并操作;首先移动父结点中的元素(该元素在两个需要合并的两个结点元素之间)下移到其子结点中,然后将这两个结点进行合并成一个结点。所以在该实例中,咱们首先将父节点中的元素【4】下移到已经删除【5】而只有【6】的结点中,然后将含有【4】和【6】的结点和含有【1】,【3】的相邻兄弟结点进行合并成一个结点。
在这里插入图片描述
也许你认为这样删除操作已经结束了,其实不然,在看看上图,对于这种特殊情况,你立即会发现父节点只包含一个元素【7】,没达标(因为非根节点包括叶子结点的元素K必须满足于2=<K<=4,而此处的K=1),这是不能够接受的。如果这个问题结点的相邻兄弟比较丰满,则可以向父结点借一个元素。而此时兄弟节点元素刚好为2,刚刚满足,只能进行合并,而根结点中的唯一元素【13】下移到子结点,这样,树的高度减少一层。
在这里插入图片描述

应用

B-树主要用于文件系统以及部分数据库索引,比如著名的非关系型数据库MongBD

而大部分关系型数据库,比如MYSQL,则使用B+树作为索引,之后再介绍

参考:
https://zhuanlan.zhihu.com/p/54084335

B树、B+树详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值