数据结构之B树查找、插入、删除详解

目录

一、概述

二、B树的查找

三、B树的插入

四、B树的删除

五、总结


一、概述

B树,也称为B-树、B_树,它是一种多路平衡查找树,B树中所有节点的孩子节点数的最大值成为B树的阶,B树是在二叉搜索树的基础上演变过来的一种数据结构。

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树,它或者是空树,或者是满足下列性质的树:

  • 树中每个节点至多有m颗子树,即每个节点最多可以有m-1个关键字(可以存放的键值对);
  • 根节点最少有2颗子树,即至少含有1个关键字,最多可以有m - 1个关键字;
  • 除了根节点以外的非叶子节点至少有【Math.ceil(m/2)】颗子树,即至少有【Math.ceil(m/2)-1】个关键字;
  • 每个节点的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它;
  • 所有叶子节点都位于同一层,或者说根节点到每个叶子节点的长度都相同;
  • 每个节点都存有索引和数据,也就是每个节点中存储了关键字(key)和关键字对应的数据(data),以及孩子结点的指针;

所以,根节点的关键字数量范围:1 <= k <= m-1,非根节点的关键字数量范围:Math.ceil(m/2) - 1 <= k <= m-1(注:ceil()是个向上取整的函数,如ceil(1.1)结果为2)。

另外,描述一颗B树时需要指定它的阶数,阶数表示了一个节点最多有多少个孩子节点。示例:

有一个5阶的B树,根据上面的规则,可知根节点关键字数量范围:1 <= k <= 4,非根节点关键字数量范围:2 <= k <= 4。

二、B树的查找

 如上图就是一颗标准的B树结构,我们以查找0005号节点为例,查找的流程大体如下:

  • 【a】首先拿到根节点【0004和0008】,与0005进行比较,因为0005大于0004,小于0008,所以需要到0004的右子树的节点继续查找(二分法规则,左小右大,左边放小于当前节点值的子节点、右边放大于当前节点值的子节点);
  • 【b】将0005节点与0006节点进行比较,因为0005小于0006,所以应该到0006左边的树中进行查找;
  • 【c】将0005节点与0005节点进行比较,刚好相等,于是就找到了目标节点;

注意:如果树结构里面没有包含所要查找的节点则返回null,总体来说,B树的搜索流程跟普通二叉搜索树的搜索流程大体类似。

三、B树的插入

插入操作是指插入一条记录,即(key, value)的键值对。如果B树中已存在需要插入的键值对,则用需要插入的value替换旧的value,若B树不存在这个key,则一定是在叶子结点中进行插入操作。

B树插入的流程:

注意:当阶数m为偶数时,需要分裂时就不存在排序恰好在中间的key,那么我们选择中间位置的前一个key或中间位置的后一个key为中心进行分裂即可。

B树插入遵循的规则:

  • (1)节点拆分规则:将节点的中间的key将这个节点分为左右两部分,中间的节点放到父节点中即可。如果是要组成一个5路查找树,那么此时m=5,关键字数必须<=5-1(这里关键字数>4就要进行节点拆分(分裂));
  • (2)排序规则:满足节点本身比左边节点大,比右边节点小的排序规则;

示例:构造一个5阶B树,插入序列为【2、7、31、11、25、29、60、28】,根据上面的规则,如果关键字的数量大于4时我们就需要进行分裂操作了,下面是详细的构造过程:

【a】先插入 2、7、31、11

插入后如下图:

 【b】插入25

 

可见插入25后,关键字的数量已经超过4个,所以需要进行分裂: 将插入后的节点中最中间的节点提取出来到父节点,然后分裂前该节点左边的子树构成一个左子树指向父节点11,分裂前该节点后边的子树构成一个右子树也指向父节点11。

【c】插入29

可见插入29后,关键字满足条件,无需分裂。

【d】插入60

可见插入60后,关键字满足条件,无需分裂。 

【e】插入28

 可以看到,当插入28后,关键字数量为5,已经大于最大值4,所以需要以中间节点【29】为中心进行分裂,然后将【29】上提到父节点,并指向分裂后的左右两边的子树。

 下面是上述示例中B树插入整个过程图:

我们对照一下网站可视化构建的B树,验证下我们上述的构建过程是否正确:

可见,上述我们的B树构建过程跟网站自动生成的一致,说明我们的构建过程没有问题。

四、B树的删除

B树的删除比插入复杂一些,因为删除之后还涉及到移动元素的操作,如果树中需要删除的key不存在,则删除操作失败。

B树删除的一些规则如下图所示:

下面以5阶B树为例,介绍B树的删除操作:

原始B树结构如下图所示:

 【a】删除21

删除21节点后,子树还剩下2两个关键字,不需要进行元素移动,所以这次删除操作直接删除21即可。

【b】删除27

由于27是非叶子节点,所以我们得先找出27的后继节点28,用28去替换27的位置,然后删除28即可。 

然后删除28,删除后如下图:

删除后发现,当前叶子结点的记录的个数小于2,而它的兄弟结点中有3个记录(当前结点还有一个右兄弟,选择右兄弟就会出现合并结点的情况,不论选哪一个都行,只是最后B树的形态会不一样而已),我们可以从兄弟结点中借取一个key。所以父结点中的28下移,兄弟结点中的26上移,删除结束。结果如下图所示: 

【c】删除32

 可见,删除之后,31子树只有一个关键字,所以需要进行元素移动。

当删除后,当前结点中只有一个key,而左右两边的兄弟结点中也仅有2个key,不能借了。所以只能让父结点中的30下移和这个两个孩子结点中的key合并,成为一个新的结点,当前结点的指针指向父结点。结果如下图所示。 

【d】删除40

可见,当前节点的关键字数量小于2,并且兄弟结点中没有多余key的借,所以父结点中的key下移,和兄弟节点合并,合并后的指向当前结点的指针就指向了父结点,如下图:

但是上图中的41节点也不满足关键字数量大于2的限制,所以同理,父节点下移,然后和左边的兄弟节点合并成一个新的节点,如下图:

 

至此,合并后结点当前结点满足条件,删除结束。

上述示例中B树删除整体流程图如下:

五、总结

以上就是关于B树查找节点、插入新节点、删除指定节点的详细构建过程总结,小伙伴们在学习的时候,不妨试试画一下,可以加深对B树结构的理解,希望本文能对大家学习B树有所帮助。由于笔者水平有限,文中可能存在不对之处,还望大家之处,一起学习,一起进步!下面推荐一个动态构建B树结构的网站,可以观察B树具体是怎么查找、插入和删除节点的:

https://www.cs.usfca.edu/~galles/visualization/BTree.html

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值