个人对B树的理解

前言

动态查找树有多种,二叉查找树、平衡二叉查找树、红黑树等。这些树的时间复杂度都为O(log2H),和树的深度有关,所以减小树的深度就可以提升查找的性能。由此就诞生了B树。

定义

B树,又称平衡多叉查找树。对于一个m阶的B树它必须满足以下一些特性:

  1. 每个节点最多只能存在m个子节点(或是子树)。
  2. 每个非叶子节点(根节点除外),都至少有ceil[m/2]个子节点(或是子树)。
  3. 根节点如果是非叶子节点,那它至少存在2个子节点(或是子树)。
  4. 非叶子节点如果存在k个子节点(或是子树),那么它就包含k-1个key。
  5. 所有叶子出现在同一层。

《个人对B树的理解》

每个非叶子节点的key都充当分割值,将其子树分开。图中7、16就是两个key,将子树分割成了三块(<7、7<x<16、>16)。

查找

B树的查找类似与二叉查找树,从根节点自上而下的递归查询,在每一层上都按照key的大小来查找自己想要的子树。一般地,会在查找key的子树时使用二分查找法来提高性能。

插入

所有的插入都是从叶子节点开始的,必须先搜索树,查找到新节点应该插入的叶子节点,并将新的节点按照以下的规则插入到树中:

  1. 如果节点包含的元素数量小于最大允许的数量,那么直接按照相应顺序插入新节点即可。
  2. 如果节点是满的情况,必须先将其分成两个子树:
    1. 从叶子节点和新节点中选出一个中值。
    2. 小于中值的放入到新的左子树中,大于中值的放入到新的右子树中,中值作为新的分割值。
    3. 新的分割值被插入到父节点中(也可能出现分裂的情况),如果不存在父节点,那么将其作为根节点,这也是B树增加高度的唯一途径。

例:往树中依次插入1~7。

《个人对B树的理解》

删除

删除过程中需要考虑以下情况:

  1. 删除的节点存在子树,即删除非叶子节点。
  2. 删除节点可能会导致当前子树的元素个数小于最小允许的元素个数。
删除叶子节点

  1. 搜索找到需要删除的元素位置。
  2. 如果是叶子节点,直接删除该节点。
  3. 删除后,如果出现了子树元素个数小于最小允许的元素个数,那么执行“删除后重平衡”对树进行重平衡。
删除内部节点

因为内部节点是左右子树的分割值,左子树都比分割值小,右子树都比分割值大。所以我们需要找到一个新的分割值来对左右子树进行重新分配。

  1. 从左右子树中找到一个新的分割值(不是左子树的最大值,就是右子树的最小值),将其从原子树中删除,并使用该节点代替需要删除的内部节点。
  2. 前面步骤删除了一个节点,如果该节点所在子树不满足条件了(子树元素个数小于最小允许的元素个数),那么执行“删除后重平衡”对树进行重平衡。
删除后重平衡

如果从节点中删除一个元素使其元素个数小于最小值,那么就需要对其进行重新分配,是树达到平衡。通常,重新分配会从一个大于个数最小值的兄弟节点中移动元素,这种操作称之为旋转。如果不存在这样的兄弟节点,那么需要将兄弟节点和该节点进行合并,并导致父节点失去一个元素,因此父节点也可能会出现缺陷,需要重新再平衡,直到缺陷的节点为根节点为止(因为根节点没有最小元素个数的限制)。

具体的步骤如下:

  • 如果缺陷节点的右兄弟节点存在,并且节点元素数量大于最小元素个数要求,则进行左旋:
    1. 将缺陷节点和右兄弟节点的共同父节点的分割值复制到缺陷节点的末端。(此时原缺陷节点没有缺陷)
    2. 将右兄弟节点的第一个元素代替原先父节点的分割值。(此时右兄弟节点也没有缺陷)
    3. 此时树已经达到平衡状态。
  • 如果缺陷节点的左兄弟节点存在,并且节点元素数量大于最小元素个数要求,则进行右旋:
    1. 将缺陷节点和左兄弟节点的共同父节点的分割值复制到缺陷节点的末端。(此时原缺陷节点没有缺陷)
    2. 将左兄弟节点的第一个元素代替原先父节点的分割值。(此时左兄弟节点也没有缺陷)
    3. 此时树已经达到平衡状态。
  • 如果缺陷节点的左右兄弟节点都只有最小的元素个数,那么进行合并,并将他们的共同父节点的分割值取出来:
    1. 将分割值放在左子树的末端。(左子树有可能是缺陷节点,也有可能是拥有最小元素个数的节点)
    2. 将右子树的所有节点移动到左子树上。(此时左子树拥有最大元素个数,右子树为空)
    3. 将分割值和右子树删除,此时父节点失去一个值。
        1). 如果父节点是根节点,且现在该节点为空,则释放它,使合并后的节点成为根节点。
        2). 如果父节点元素个数小于最小元素个数,那么需要对父节点进行重平衡。

总结

B树通过以上的这些特性以及增删查的策略,使得B树在大量数据下的增删查的效率很高,当然也存在一些缺陷,比如查询只能从根节点一个一个的查,导致查询某个范围数据的性能很低等。从B树衍生出的B+树就解决了该问题。

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