数据结构——B+树

一、B+树的概念

B+树是应数据所需而出现的一种B树的变形树。一棵m阶的B+树需要满足下列条件:

  1. 每个分支节点最多有m棵子树(孩子节点);
  2. 非叶根节点至少有两棵子树,其他每个分支节点至少有⌈m/2⌉棵子树;
  3. 节点的字数个数与关键字个数相等;
  4. 所有叶节点包含全部关键字及指向相应记录的指针,叶节点中将关键字按大小顺序排列,并且相邻叶节点按大小顺序相互链接起来;
  5. 所有分支节点(可视为索引的索引)中仅包含他的各个子节点(即下一级的索引块)中关键字的最大值及指向其子节点的指针。

二、B+树和B树的差异

  1. 在B+树中,具有n个关键字的结点只含有n棵子树,即每个关键字对应一棵子树;而在B树中,具有n个关键字的结点含有n+1棵子树。
  2. 在B+树中,每个节点(非根内部节点)的关键字个数n的范围为⌈m/2⌉~m(而根节点:1~m);而在B树中,每个节点(非根内部节点)的关键字个数n的范围为⌈m/2⌉-1~m-1(根节点:1~m-1)。
  3. 在B+树中,叶节点包含了全部关键字,非叶节点中出现的关键字也会出现在叶节点中;而在B树中,最外层的终端节点包含的关键字和其他节点包含的关键字是不重复的。
  4. 在B+树中,叶节点包含信息,所有非叶节点仅起索引作用,非叶节点的每个索引项只含有对应子树的最大关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。
    数据结构——B+树_第1张图片

三、B+树的查找

B+树中的所有数据均保存在叶子结点,且根结点和内部结点均只是充当控制查找记录的媒介,并不代表数据本身,所有的内部结点元素都同时存在于子结点中,是子节点元素中是最大(或最小)元素。

例如在上图中的B+树中查找55这个关键字,步骤如下:

  • 在根节点中对比55和根节点中的元素[60, 85],发现55<60,因此应该在第一个结点中继续寻找;
  • 同理,比较55和第一个节点中的元素[10, 20, 50, 60],发现50<55<60,因此55应该存在于第四个结点当中;
  • 继续对比55和第四个结点中的元素[55, 60],找到55,查找成功。当然,也有查找失败的情况,即要查找的元素并不在B+树中。

四、B+树的插入

B+树的插入和B树十分相似,其插入规则如下:

  • 插入的操作全部都在叶子结点上进行,且不能破坏关键字自小而大的顺序;
  • 当插入关键字后结点的关键字个数大于m,需要进行“分裂”。
    B+树的插入有四种情况:
  1. 若被插入关键字所在的结点,其含有关键字数目小于m,则直接插入;
  2. 若被插入关键字所在的结点,其含有关键字数目等于m,则需要将这个结点分为左右两部分,中间的结点放到父节点中。假设其双亲结点中包含的关键字个数小于 m,则插入操作完成。
  3. 在第 2 种情况中,如果上移操作导致其双亲结点中关键字个数大于 M,则应继续分裂其双亲结点。
  4. 若插入的关键字比当前结点中的最大值还大,破坏了B+树中从根结点到当前结点的所有索引值,此时需要及时修正后,再做其他操作。

举例:
数据结构——B+树_第2张图片
(1) 插入关键字12,此时第一个叶子节点部分[10, 15]关键字的个数数据结构——B+树_第3张图片
(2) 插入95,需要插入到最后一个叶子节点部分[85, 91, 97]:
数据结构——B+树_第4张图片
此时该节点的关键字个数大于m,需要进行分裂操作,并且父节点需要插入一个新的关键字:
数据结构——B+树_第5张图片
(3) 插入40,需要插入到第二个叶子节点部分[21, 37, 44]:
数据结构——B+树_第6张图片
此时该节点的关键字个数大于m,需要进行分裂操作,并且父节点需要插入一个新的关键字:
数据结构——B+树_第7张图片

父节点插入新的关键字之后,关键字的个数大于m,也需要进行分裂:
数据结构——B+树_第8张图片
(4)插入100,由于其值比最大值 97 还大,插入之后,从根结点到该结点经过的所有结点中的所有值都要由 97 改为 100。(橙色为修改之后的)
数据结构——B+树_第9张图片
修改完最大值之后,在最后一个节点处插入100:
数据结构——B+树_第10张图片

五、B+树的删除

B+树的删除也和B树十分类似,它有下面几种情况:

  1. 找到存储有该关键字所在的结点时,由于该结点中关键字个数>=⌈m/2⌉,做删除操作不会破坏 B+树,则可以直接删除;
  2. 当删除某结点中最大或者最小的关键字,就会涉及到更改其双亲结点一直到根结点中所有索引值的更改。
  3. 当删除该关键字,导致当前结点中关键字个数小于 ⌈m/2⌉,若其兄弟结点中含有多余的关键字,可以从兄弟结点中借关键字完成删除操作。
  4. 第 3 种情况中,如果其兄弟结点没有多余的关键字,则需要同其兄弟结点进行合并。
  5. 当进行合并时,可能会产生因合并使其双亲结点破坏 B+树的结构,需要依照以上规律处理其双亲结点。

举例:
数据结构——B+树_第11张图片
(1)删除12,包含12的叶子节点的关键字个数为3,当删除12时,关键字个数仍然大于等于⌈m/2⌉,可以直接删除:
数据结构——B+树_第12张图片
(2)删除97,97为整个B+树中元素最大的值,当删除这个元素时,需要修改从97的父节点到根节点中所有涉及到97的值,将其修改为第二大的元素值(在这个例子中第二大的元素为91):
数据结构——B+树_第13张图片
(3)删除51,此时51所在的结点只有59一个元素,该节点的关键字个数小于⌈m/2⌉,而它的兄弟结点元素个数大于⌈m/2⌉,可以给该节点借一个:
数据结构——B+树_第14张图片
此时第二个叶子节点中的最大关键字为37,因此需要修改其父节点的值:
数据结构——B+树_第15张图片
(4)删除59,此时59所在结点的关键字个数小于⌈m/2⌉:
数据结构——B+树_第16张图片
并且该结点的兄弟结点的个数都为⌈m/2⌉,无法给它借关键字,因此将该结点与兄弟结点进行合并,结点合并之后,需要注意修改祖先节点相关的值:
数据结构——B+树_第17张图片
(5)删除63,此时63所在的结点关键字个数小于⌈m/2⌉,并且兄弟节点无法给该节点提供关键字,因此该节点和其兄弟结点进行合并:
数据结构——B+树_第18张图片
此时从图中可以发现,合并后的结点的父节点应该删除72,这时父节点关键字的个数小于⌈m/2⌉:
数据结构——B+树_第19张图片
并且此时91所在结点的兄弟节点无法给该节点提供关键字,因此该结点和兄弟结点合并,并且需要修改合并后的节点的父节点的关键字值,合并后的结点的关键字个数满足条件。
数据结构——B+树_第20张图片

六、B+树使用场景

  • B+树是在B树的基础上改造的,它的数据都在叶子节点,同时叶子结点之间还加了指针形成链表,多用于数据库索引
  • 在数据库中通常不只是查询(select)一条记录,如果是多条记录的话,B树要做中序遍历,可能要跨层访问,而B+树由于所有的数据都在叶子节点,不用跨层,同时由于有链表结构只要找到首尾,就能通过链表把数据都读出来。

你可能感兴趣的:(数据结构,数据结构,b+树)