B+树的概念以及操作

B+ 树是一个多叉树排序树,其每个节点中可能包含多个 key。主要是用来对 OLTB 的数据库来进行索引。对于 insert, delete 操作需要调整树的结构保证这棵树的平衡性,使其所有的叶子节点的深度都是一样的。与此同时需要让每个节点有一定数量的 key 不能过多,也不能过少。 (todo 补充B+树的意义)。

1 B+ 树的性质

  • insert delete 操作需要保证这棵树的平衡性。
  • 除根节点外的每个节点至少保证 50% 空间被 key 占用。
  • 对于查询操作,只需要访问树的高度个节点。
  • 假设每个节点有 m 个 key, 对于非根节点 d \leq m \leq 2d, 其中 d 是 B+ 树的参数,叫做树的 order 用来定义节点的容量。对于根节点 1\leq m \leq 2d.

2 B+ 节点的 format

B+ 树有两种节点,中间节点叶子节点,共同点是他们都包含了 key,不同点是,中间节点包含了指向子树的指针。**叶子节点没有指向子树的指针, 但是包含了 key 所对应的 record 或者是指向 record 的指针。并且叶子节点有指向其 相邻的叶子节点的指针(用来遍历 B+ 树)。

非叶子节点m 个 key 和 m+1 个指针P_i指向子节点。所有的 key 都是以什序排列 K_{i} < K_{i+1} < K_{i+2}, 其中 P_0 指针指向的子树的所有的 key 都小于 K_1, K_0 不存在。其他指针 P_m 指向的子树的 key 的值大于等于 K_m。下图就是一个 2d = 4 B+ 树的例子。

image

当然叶子节点也可以作为根节点,下图就是只插入三个 key 时 B+ tree 的样子。

image

注意:本文中的后续举例说明的 B+ 树的 d 默认为 2。

3 插入操作

B+ 树插入的 entry 一般包含了一个 key 与一个 val。

首先找到应该插入的叶子节点,并将 <key,val> 插入。

如果插入后的叶子节点的 m>2d ,需要将将节点分裂(split)为 d 与 d+1 两个节点,并且将右边节点的 lowKey(最小的key)插入到父亲节点。

split 需要分三种情况讨论:

1)被 split 的节点没有父亲节点,即根节点为叶子节点。需要创建一个 中间节点作为根节点,并且将 split 的 pivot 插入到这个新的根节点,其两个指针分别指向 split 出来的两个新的叶子节点。

如下图,是一个 d=2 的 B+ 树,继续插入一个<8:4> 的pair:

image

树将变为下面的样子:

image
  1. 如果有父亲节点且父亲节点没有满,被split 出来新的节点 pointer 和 split 的 pivot 插入父亲节点。如下图向上图中的 B+ 树中连续插入 <10,5>和 <12,6> 两个 entry将得到下图的结果。
image

3)如果父亲节点已经插满,父亲节点也需要分裂递归向上插入 split 出来的 node 与 pivot

image

如果向上图插入<17,4> 这个 entry 会导致节点分裂,并且 pivot 为 key = 15。此时其父节点中上插入 key=15, 以及 pointer 指向被分裂出来的 node 。而在父亲节点插入的新 <key,pointer> 会导致父亲节点进行分裂,并且同样在 key = 15 处分裂。此时由于父亲节点没有父亲节点了,创建一个新的 root 节点。如下图:

image

⚠️ 这里需要注意:

split 中间节点操作与 split 叶子节点有少许的不同,叶子节点会将 pivot 插入父亲节点,并且保留这个 pivot。而对于中间节点来说,这个pivot 在插入父亲节点后,在当前节点中会被移除掉。

4 删除操作

当删除某一个 key 后,可能会导致叶子节点 m < d 需要改变树的结构以满足 B+ 树的定义。这里涉及到两种可能的操作,使得 B+ 树满足定义。他们为: 重排(redistribute) 和 合并 (merge) 。

删除key的操作是通过递归实现。对从根节点到key所在的叶子节点递归调用删除操作。如果子树的删除操作不会导致点该节点中 key 的数量过小即 m < d 就直接返回。反之需要对该节点进行 redistribute 或者 merge。

首先尝试 redistribute 即分别向左右 sibling (同一个parent 下面的节点) 一个 key 让当前节点满足 B+树的要求。可以 lend 的 sibling 需满足 m > d。如果找不到这样的 sibling 则说明要么没有 sibling 要么 sibling (m < d) 。则此时可以尝试 merge。

下面将删除操作分别在叶子节点和中间节点中运用进行讨论,即删除后节点的 m < d

4.1 叶子节点

4.1.1 redistribute
4.1.1.1 向左兄弟借一个key

如果当前节点不是其父亲节点的最左的儿子,并且其左边的兄弟的 key 的数量 m > d,向其左兄弟借一个 key(左兄弟的最大的key), 更新当前节点的父亲节点指向当前节点所对应的key。例如对上图的B+树中删除 <20,4> 这个值,其所在的节点会向其左兄弟借 <17,4>这个 entry 并将父亲节点中的 key 从 20 改为 17。

image
4.1.1.2 向右兄弟借一个 key

如果当前节点不是其父亲节点的最右边的儿子,并且其右边的兄弟的 key 的数量 m > d,向其右兄弟借一个 key(左兄弟的最小的key),更新父亲节点指向右兄弟的 pionter 所对应的 key。例如如果删除上图中的 <21,4> 这个 key,这个节点将会向右兄弟借 <22,4> 这个key 父亲节点中的 22 将更新为 25.结果如下图所示:

image
4.1.2 merge
4.1.2.1 merge 到左兄弟

如果当前节点有左兄弟,并且左兄弟的 key 的数量 m \leq d,将当前节点上的key copy 到左兄弟,删除当前节点,并且在父亲节点将当前节点的 pointer 以及 key 删掉。

image

例如将上图中 删除 21, 所在的节将 merge 其左兄弟,父亲节点的keys 将删除 18 以及 当前node 的 pointer,最后parent只剩下 23,25,如下图。

image
4.1.2.2 merge 右兄弟

如果不能merge到左兄弟(当前节点为 parent 最左边的儿子) merge 其右兄弟。 在父亲节点中将右兄弟的 pointer 以及key删除掉。如果将 4.1.1.3 中的第一张图的 <16,4> 删除,将会导致其节点 merge 右边的兄弟,其父亲节点将变为 [23,25].

image

4.2 中间节点

上面的部分只讨论了叶子节点出现 redistribute 和 merge的情况。在某些情况下这些操作将会导致中间节点的 key的数量不满足 B+ 树的要求。此时需要将中间节点进行 redistribute 或者merge。例如上图中如果删除 25 将会导致叶子节点的merge,其父亲节点将会只有一个 key。这将不能满足B+树的限制。

4.2.1 redistribute
4.2.1.1 向左兄弟借一个 key
image

由于中间节点的每一个 entry 是 <key,pointer> 的组合,如果直接将左兄弟的最大的key以及它所代表pointer copy 过来会导致当前节点少了一个 key, 此时需要将父亲节点所对应的 key copy 到中间。并且更新父亲节点中,指向当前节点的 pointer 所对应的 key为借过来的 key。例如,将上图中的 17 删除掉,将会导致 [20,22]这个节点的变为 [22], 需要向左边的兄弟借一个 10 的key过来,并且将父亲节点的 15 copy 下来,最终变为 [10,15,22],并更新父亲节点的 key。如下图所示:

image
4.2.1.2 向右边兄弟借一个 key

同理,需要将右兄弟的在父亲节点中pointer 说对应的 key copy 下来,并且更新父亲节点的 key。稍微有点区别的是,右边兄弟的第一个儿子的指针是不包含 key 的,所以当前节点只需要将指针直接拿过来,并删除掉 right silbing 最小的那个key。

image

如图,如果将图中的 10 删除,会导致 [5,10] 这个节点变为 [5] 并向右边的兄弟借一个pointer,并且父亲节点中key被更为 17。

image
4.2.2 merge

merge 的操作和 redistribute 的操作类似,redistribute 是只borrow 一个 key, 而merge 是将所有的 key 都 borrow 过来。稍有一点区别就是 borrow 是 update 父亲节点中的 key, 而 merge 是直接删除,可以看作是 split 的逆过程。

image
4.2.2.1 merge to left

如上图如果删除 18 [24,30] 这个节点将变为 [30], 会把当前节点 merge 到左边的 [6,12] 这个节点, 最后变成 [6,12,18,30] 这个节点,如下图所示。

image
4.2.2.1 merge right

如果删除 15 会将右边的节点 merge 过来 当前节点变为[6,18,24,30],如下图所示。

image
4.2.2.2 root 变为 空

如何递归删除到根节点时(m=2),并且两个子节点发生 merge,这样会导致根节点的key 的数量为零,此时就需要删除根节点。

例如删除下图中的 9 这个key 会让两个子节点 merge。

image

删除后的B+树如下图:

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 0.目录 1.算法导论的红黑树本质上是2-3-4树 2.红黑树的结构和性质 3.红黑树的插入 4.红黑树的删除 5...
    王侦阅读 2,477评论 1 2
  • 1、2-3-4树 在二叉树中,每个节点有一个数据项,最多有两个子节点。如果允许每个节点可以有更多的数据项和更多的子...
    冰河winner阅读 1,966评论 1 6
  • 红黑树是平衡二叉查找树的一种。为了深入理解红黑树,我们需要从二叉查找树开始讲起。 BST 二叉查找树(Binary...
    kanehe阅读 1,374评论 0 8
  • 本文转载自博客,因为题主写的已经很详细了。 写在前面的一点,面试专用(m阶指的是每个节点最多有m个子树)。 一个m...
    放开那个BUG阅读 1,172评论 0 5
  • 本文摘录及参考自: 1. 学习Javascript闭包(Closure)2. 闭包的秘密3. JavaScript...
    9979eb0cd854阅读 146评论 0 0