查找树(四):B-树和B+树

1. 磁盘I/O问题

众所周知,相较于计算机指令的执行速度,访问磁盘所带来的开销是十分巨大的。对于一段需要访问磁盘的程序,程序运行的时间几乎都花费再了磁盘的I/O上。 也就是说,在这种情况下,如果我们可以将磁盘的访问次数减少一般,那么程序的运行时间也将减半。

当数据量较少,可以完全存储在内存时,数据的访问相对来说是比较快的,类似AVL树红黑树等数据结构可以将操作数据的时间复杂度控制在O(log2N)。当数据量很大时,无法将其存储在内存当中,只能退而求其次,存储在磁盘中;由于磁盘I/O速度的限制,此时大O模型将不再适用,磁盘的I/O次数决定了程序的时间成本。

针对数据被存储在磁盘中的情况,常规的平衡二叉树已经不能很好的满足我们的需求。因此,我们需要一种新的查找树结构,这种新的树结构可以在相同数据量时拥有更低的高度(树的高度决定了数据操作的最大访问次数)。

2. B-树

为降低树的高度,很自然的一个想法就是让树有更多的分支,B-树就遵循了此想法——既然一个节点有两个分支不够,那就让它拥有尽可能多的分支。B-树的所有节点都携带数据(这也是它和B+树的主要区别),由于它是一颗查找树,因此需要一个“排序”的依据,将此排序的依据成为关键码,每个关键码都关联着具体的数据元素。也就是说,节点的关键码个数也代表着节点存储的数据元素的个数。

B-树又被称为B树,B代表Balanced,即平衡的意思。一棵M阶的B-树有如下的特点:

  1. 根节点或是一片叶子,或是拥有 2 到 M 个个孩子;
  2. 除根外,所有非叶子节点都包含k-1个关键码和k个孩子,其中 ceil(M/2) <= k <= M(ceil表示向上取整,如ceil(2.5) = 3);
  3. 每一个叶子节点都包含k-1个关键码,其中 ceil(M/2) <= k <= M;
  4. 所有的叶子结点都位于同一层;
  5. 每个节点中的关键码都遵循从小到大的排列,节点中的k-1个关键码正好可以划分出k个孩子。

单纯的看B-树的定义显得比较的抽象,可以通过具体的插入和删除操作进一步的理解B-树的结构。

2.1 B-树的插入操作

简单的来说,B-数的插入操作可以分为以下几种情况:

  • 插入后不破坏B-树规则,则直接插入;
  • 插入后该节点的关键码个数超出规定范围(M-1),则进行分裂操作;
  • 分裂操作后相当于父节点插入了一个新元素,递归的向上执行插入逻辑。

以M = 5为例(即一颗5阶的B-树),图例中蓝色代表新插入的元素,绿色代表插入前就已经存在的元素:

  1. 向空树中插入2(插入根节点):
    在这里插入图片描述
  2. 继续依次插入1、10、3(找到合适的位置插入即可),可以看到根节点中的关键码遵循从小到大的排列
    在这里插入图片描述
  3. 继续插入9后,此时根节点的关键码个数增加到5个(大于M-1),需要执行分裂操作(找到位于中间的关键码,进行拆分),分裂后根节点与其子树均符合B-树的特性:
    在这里插入图片描述
  4. 继续插入18、12、44,又一叶节点的关键码达到5个,继续分裂,中间元素被“上提”到父节点
    在这里插入图片描述

查找树的插入操作一般都会选择将新元素作为叶子节点插入,每次插入后,如果没有破坏B-树的规则,则插入结束;如果破坏了B-树的规则(插入操作中主要指关键码个数超出规定),则向进行分离操作,然后递归的检查父节点是否符合B-树的规则

2.2 B-树的删除操作

一般来说,删除操作都会比插入操作更加的复杂,B-树也是如此。简单的来说B-树的删除可以分为以下几种情况:

  • 被删除的关键码位于叶子节点,且删除后不破坏B-树规则,则直接删除;
  • 被删除的关键码位于叶子节点,删除后该节点关键码个数小于ceil(M/2)-1,则根据其兄弟节点的关键码个数,执行借关键码(兄弟节点的关键码足够)或合并(兄弟节点的关键码不足)操作;
  • 合并叶子节点后,父节点的关键码-1,相当于删除了内部节点的关键码,递归的执行删除逻辑即可;
  • 被删除的关键码位于内部节点,则根据该关键码的左右子节点的关键码个数,执行借关键码(子节点的关键码足够)或合并(子节点的关键码不足)操作;类似的,合并后递归的向上执行删除逻辑。

继续以M = 5为例,首先构造了一颗元素“较多”的B-树,然后对其进行删除操作,被删除的元素被表示为红色:

  1. 构造了一颗5阶的B-树:
    在这里插入图片描述
  2. 删除3,由于被删除的关键码存在于叶子节点,且删除后关键码个数符合B-树的规则,因此可以直接删除:
    在这里插入图片描述
  3. 删除25,删除后该叶子节点的关键码数为1,小于ceil(M/2)-1,此处需要根据其兄弟节点是否有足够的关键码(大于等于ceil(M/2)),有则向兄弟节点借一个,没有则进行合并操作。显然该节点的右兄弟存在足够的关键码,因此只需要向兄弟节点“借“一个关键码即可(父节点下移一个关键码,兄弟节点上移一个关键码):
    在这里插入图片描述
  4. 删除98,删除后面临和3中类似的情况,不同的是该叶子节点的兄弟节点没有足够的关键码可以借给它。此时,需要将该节点、该节点的兄弟节点以及父节点对应的关键码进行合并。合并操作会让父节点的关键码-1(相当于内部节点删除了一个元素),如果合并后父节点的关键码数不足,则递归的执行内部节点的删除操作
    在这里插入图片描述
  5. 删除31,被删除关键码所处的节点为内部节点,从内部节点中删除关键码首先需要观察“关键码对应的左右子节点”是否有足够的关键码,有则向子节点借一个,没有则进行合并。显然,此时31的右子节点有足够的关键码:
    在这里插入图片描述
  6. 删除31,删除后面临和5中类似的情况,不同的是此时子节点没有足够的关键码,因此执行合并操作。合并后父节点关键码-1,递归的向上执行删除逻辑:
    在这里插入图片描述

3. B+树

B+树是B-树的变体,也是一种多路搜索树,它与B-树类似,并规定了:

  • 非叶子节点不保存指向数据的指针,只进行数据索引(简单的来说就是只存放关键码,不保存数据);
  • 为所有叶子结点增加了一个链指针;
  • 内部节点中一个关键码对应一个子节点(B-树中子节点个数比关键码个数多1),关键码是子节点中最大(或最小)的元素。

也就是说,B+树的数据都被保存在了叶子节点中,为什么要这么做呢?

回顾引入B-树的过程,选取B-树的初衷是为了降低树的高度,以减少磁盘I/0的次数。一般来说,树的每一个节点都对应着一个磁盘区块,节点中存储元素的大小限制了节点存储元素的个数,即影响了最终所获的树的高度,从而影响磁盘I/O的次数。 B-树中的每个节点都保存着关键码和指向数据的指针,它们共同构成了前面所说的“元素”,如果可以减小元素的大小,就可以进一步的降低树的高度。

由于多路查找树的增删查操作都依赖于关键码,因此关键码是必须保留的,但数据指针在查找过程中却不是必须的,因此可以只保存在叶子节点中。B+树就是遵循了此原理,它的内部节点只保存了关键码(以及子节点的索引),不保存数据指针,所有的数据都被保存在了叶子节点中:

  • 使B+树获得更低的高度,从而减少磁盘I/O的次数
  • 由于数据都存储在叶子节点中,且叶子节点都位于同一层,所以查找操作是稳定的(每一次查找都需要相同的次数);
  • 同时,因为所有叶子节点形成了一个有序链表,范围查询变得更加便利了。

下面给出了一个B+树了示例:
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
B树、B-B+树都是一种平衡的多路查找,用于在磁盘等外部存储设备中进行高效的查找操作。 B树是一种平衡的多路查找,每个节点可以存储多个数据,并且每个节点可以有多个子节点。B树的每个节点存储了一定的范围区间,这样可以加快搜索速度。例如,对于1~100的索引值,B树可以将其划分为多个区间,从而一次性排除大部分数据,使搜索更加高效。 B-B树的一种变体,它的每个节点可以存放多个数据和子节点,并且相邻的叶节点之间可以相互连接,这样可以增加区间访问性能,适用于范围查询等操作。 B+树也是B树的一种变体,与B树和B-不同的是,B+树的叶子节点之间互相连接,而非叶子节点只存储索引信息,数据只存在于叶子节点中。这样可以提高区间查询的性能,并且也适用于范围查询等操作。 总结来说,B树、B-B+树都是一种平衡的多路查找,用于在磁盘等外部存储设备中进行高效的查找操作。它们的区别在于节点的存储方式和叶子节点的连接方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [B-B树B+树](https://blog.csdn.net/weixin_42386551/article/details/117604839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [B-B+树的区别](https://blog.csdn.net/liuyuan1999/article/details/127382525)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值