转载

腾讯、阿里面试题 了解B+树吗?

腾讯、阿里面试题: 了解B+树吗?

由于MySQL的索引结构是B+树,所以B+树是大厂的高频面试题,想理解B+树,最好先理解B树,下面详细介绍B树、B+树

B树

  • B树的概念

    B树又称为B-树,是一种平衡多路查找树,描述B树,一般需要指定其阶数 M M ,阶数指的是一个节点包含的子节点最大数量。当 M M 取2的时候,就是常见的二叉树

    其有如下性质:

    • 每个节点最多有 M ? 1 M-1 个关键字
    • 除根节点外,其余的节点至少有 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 个关键字( c e i l ceil 向上取整函数)
    • 每个结点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它
    • 所有叶子结点都位于同一层,或者说根结点到每个叶子结点的长度都相同。
  • B树的插入操作

    如下描述是B树的插入算法,相对来说比较简单

    1. 找到关键字的插入位置,一定是叶节点位置,进行插入操作

    2. 插入后,如果当前节点的关键字数量小于等于 M ? 1 M-1 ,则结束,否则执行步骤3

    3. 进行分裂操作,当前节点按中间关键字分裂成三部分,中间关键字插入到父节点中,

    左边部分,成为中间关键字的左节点,右边部分成为中间关键字的右节点,然后

    当前节点指向父节点,转到2,执行递归操作。

    下面是一个5阶B树的分裂过程,上面图是分裂前,下面图是分裂后

  • B树的构建过程

    下面以构建一个5阶树,介绍B树的构建过程。

    • 依次插入关键字3,5, 2, 6

    • 插入4的时候,由于当前节点关键字数量等于M(5),需要进行分裂操作

    • 依次插入关键字1,8,7,9插入9的时候又进行了分裂

    • 依次插入关键字10,11,12插入12的时候又进行了分裂过程

    • 插入关键字13,14,15,16,17,中间插入15的时候进行了分裂操作

    • 最后插入18,进行了两次分裂操作

      其实插入的过程会发现,顺序插入空间效率最差,比如[11,12]节点,就插入不了任何元素.

  • B树的删除过程

    B树的删除算法较为复杂,下面首先介绍算法,之后结合实例,阐述

    1. 查找关键字,如果不存在,结束,否则进入步骤2.
    2. 如果关键字处于叶节点,直接删除。如果关键字处于非叶子节点,则用其前继关键字(前继关键字一定位于叶节点)覆盖要删除的关键字,之后删除后继关键字,将当前节点指向包含后继关键字的节点。以上两种情况,均最后转入步骤3
    3. 如果当前节点关键字数量大于等于 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 ,则结束,否则转入4
    4. 如果兄弟节点(不论左兄弟,还是右兄弟),关键字数量大于 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 ,则父节点中对应的关键字下移到当前节点,兄弟节点对应的关键字上移到父节点,结束。若无兄弟节点关键字数量大于 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 ,则转入步骤5
    5. 合并操作,将父结点中关键字下移与当前结点及它的兄弟结点中的官架子合并,形成一个新的结点。原父结点中的key的两个孩子指针就变成了一个孩子指针,指向这个新结点。当前节点指向父节点,重复2,进行递归操作。

    下面是一个5阶数的删除过程实例

    原B树如下图所示

    • 删除关键字7

      其前继关键字(类似于平衡二叉树的前继节点,其实也可以为后继节点)为6,覆盖删除后,当前节点只有一个关键字5,而其左兄弟节点有3个关键字节点大于2.所以3上移,4下移到当前节点.

    • 删除关键字18

      删除关键字18,其实是一个复杂的过程,删除完之后,没有兄弟节点关键字数量大于2,所以进行合并操作左兄弟节点[14,15],父节点中的16,和当前节点合并成一个新节点[14,15,16,17],合并后父节点由于只剩13,所有又要与其父节点关键字,左兄弟节点合并,构造一个新的节点,最后结果如下

  • B树的优缺点

    B树主要的优点是相对于二叉树,每个节点包括更多的关键字,所以其树高相对较低,查找效率很高.

B+树

  • B+树的概念

    • B+树包含两种节点,一种是非叶子节点(索引节点),一种是叶子节点。
    • B+树与B树,最大的不同是B+树的非叶子节点不保存数据,只用于索引,所有数据都保存在叶子节点
    • 非叶子节点最多有 M ? 1 M-1 个关键字,阶数 M M 同时限制了叶子结点最多存储 M ? 1 M-1 个记录。
    • 索引节点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。
    • 每个叶子节点都存有相邻叶子节点的指针,叶子节点本身依关键字的大小自小而大顺序链接(范围查找特性)
  • B+树插入

    • B+树插入算法

      1. 通过查找,确定关键字的插入位置,插入位置一定位于叶节点,插入后,如果当前

        节点关键字数量小于等于 M ? 1 M-1 ,算法结束,否则转入步骤2.

      2. 分裂过程,将当前节点,分为左右两个叶子节点,左叶子节点包含前 M / 2 M/2 个记录,

        右叶子节点包含剩余记录,并且将第 M / 2 + 1 M/2+1 个记录的关键字上移到父节点。当前节点指针指向父节点,然后执行步骤3.(父节点一定是索引节点)

      3. 如果当前节点的关键字数量小于 M M ,则插入结束,否则,将当前索引节点以中间关键字为中心分裂成两个索引节点,左索引节点和右索引节点,并将中间关键字上移到父节点中。并且其左节点为上面提到的左索引节点,其右节点为右索引节点。将当前节点指针指向父节点,重复步骤3

    • B+树插入实例

      如下是一个5阶B+数的构造过程

      • 依次插入1、5、9、13

      • 插入17的时候,发生分裂过程

      • 依次插入2、3、4,插入4的时候,发生分裂过程

      • 依次插入10,11,插入11的时候,发生分裂过程

      • 插入12,14,插入14的时候,发生分裂过程

      • 插入15,16,插入16的时候,发生两次分裂过程,依次在叶节点,和索引节点

  • B+树删除

    • B+树删除算法

      1. 找到目标关键字所在的叶节点位置,进行删除,若删除后,当前节点关键字数量大于

        等于 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 ,结束,否则转到步骤2

      2. 若兄弟节点有富余(大于 c e i l ( M / 2 ) ? 1 ceil(M /2 )-1 ),向兄弟借一个记录,同时用借到的key替换父节点中对应的关键字,结束。否则转到步骤3

      3. 若兄弟节点没有富余,则当前节点和兄弟节点合并成一个新的节点,删除父节点的关键字,新节点指向父节点相应的位置。执行步骤4

      4. 若索引节点的关键字个数大于等于 c e i l ( M / 2 ) ? 1 ceil(M/2)-1 ,则结束,否则执行5

      5. 若兄弟结点有富余,父结点key下移,兄弟结点key上移,删除结束。否则执行第6步

      6. 当前结点和兄弟结点及父结点下移key合并成一个新的结点。将当前结点指向父结点,重复第4步

      4,5,6步类似B树的删除过程

    • B+树删除算法实例

      原来的一个5阶树

      • 删除10

        左兄弟节点有富余,借一个记录5,并且替换父节点中的关键字

      • 删除11

        删除11这个过程非常复杂,首先没有兄弟节点有富余,所以当前节点和兄弟节点合,并且删除掉父节点中对应的关键字,也就是13。之后由于父节点只有15一个关键字,需要一次索引节点的合并过程

        每次删除的时候,记得更新索引结构,即将索引结构中的要删除的关键字,替换成其后继节点

  • B+树的优点

    1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;

    2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;

    3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。

    4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

    B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。

参考文章

B树和B+树的插入、删除图文详解
平衡二叉树、B树、B+树、B*树 理解其中一种你就都明白了

正文到此结束
本文目录