底层数据结构(B+树 - 查找、插入和删除)

B+树插入删除示例

B+树是什么?

  • B+树是一种树;
  • B+树(或者其子树)代表一个有序的键值对集合,通过键决定键值对顺序;
  • B+树的节点有两类,一类是内部节点(interval node),不存储值,只存储键,一类是叶子节点(leaf node),既存储键,也存储值(一般存储值的指针);
  • 内部节点可以有多个儿子指针,假设最多有 n + 1个,而与之对应的,内部节点最有也有 n 个键;
  • 内部节点的键以升序(或者降序)排列,指针也依次插入在 n 个键之间,因此每一个键可以对应到两个指针上(一左一右),相邻两个键共享一个指针;
  • 假设内部节点有两个相邻的键 a_i, a_{i+1},那么其共享的指针指向的子树代表的有序集合的键在 a_ia_{i+1} 之间,确切的说在区间 [a_i, a_{i+1})内;
  • 叶子节点也包括多个儿子指针(n + 1个)和多个键(n个),每一个键对应一个指针,该指针存储键值对中值对应的地址,剩下的最后的指针指向下一个叶子节点,下一个叶子节点指的是其该叶子节点最后的键值对的下一个键值对所在的叶子节点;
  • 因此顺着某一个叶子节点的最后的指针往后走,可以遍历所有比该叶子节点第一个键大的所有键对应的键值对;

B+树的一些限制条件

  • B+树的内部节点中,至少需要有 \lfloor \frac {n} {2} \rfloor 个键(除了根节点以外);
  • B+树的叶子节点中,至少需要有 \lfloor \frac {n + 1} {2} \rfloor 个键;

B+树的查找

  • 从根节点开始顺着内部节点往下找,找到对应的叶子节点,在叶子节点上根据键找到对应的值;
  • 相邻两个键(a_ia_{i+1})中间指针指向的子树代表的集合,都在区间 [a_i, a_{i+1})内,根据该性质,找到 j 满足 a_j \leq key \lt a_{j+1},根据两个键中间的指针,继续往下进行类似的查找操作;
  • 找到对应的叶子节点后,通过遍历叶子节点包含的键值对可以找到待查找的键对应的值;如果找不到即该树中不包含该键对应的键值对;

B+树的插入

B+树插入示例
  • 因为B+树中只有叶子节点存储键值对,那么一定会在叶子节点上插入新的键值对;
  • 通过类似查找的方式找新的键值对所对应的叶子节点;
  • 将该键值对插入到该叶子节点上后(满足键升序或者降序的性质),如果该节点能够存储该键值对,那么就没有后续的处理了;
  • 否则,需要把该节点分裂成两个叶子节点,假设插入前叶子节点有 n 个键值对,那么当前有 n+1 个键值对,分裂时把前 \lfloor \frac {n+1} {2} \rfloor 个键值对放入第一个叶子节点,把后 \lceil \frac {n+1} {2} \rceil个键值对放入第二个叶子节点(此时满足限制条件),第一个叶子节点的最后一个指针指向第二个叶子节点,第二个叶子节点的最后一个指针指向前叶子节点最后指针指向的位置;
  • 此时新增了一个叶子节点,需要在前叶子节点对应的父亲节点上,新增一个键,该键的值是分裂后第二个叶子节点的第一个键的值,该键对应的两个指针(一左一右)分别指向分裂后的第一个和第二个叶子节点;
  • 如果父亲节点存不下新增的键,父亲节点也需要分裂;
  • 父亲节点作为内部节点,分裂方式和叶子节点有些区别,假设当前该节点有 n+1 个键和 n+2 个指针,新建两个内部节点,将前 \lfloor \frac {n} {2} \rfloor 个键和前 \lfloor \frac {n} {2} \rfloor +1 个指针放入第一个内部节点,将后 \lceil \frac {n} {2} \rceil 个键和后 \lceil \frac {n} {2} \rceil + 1个指针放入第二个内部节点;
  • 剩下的一个键按照上述类似的方式插入原内部节点的父亲节点,递归内部节点插入的过程;
  • 如果父节点不存在(也就是原叶子节点是根节点),那么新建一个节点充当新的父亲节点(也作为根节点);

B+树的删除

B+树的删除示例
  • 对于一个待删除的键 k,首先顺着根节点找到其所在的叶子节点(查找),如果找不到则代表该键在树中不存在;

  • 如果找到了对应的键值对,删除该键值对,如果此时节点的限制条件满足(B+树的叶子节点中,至少需要有 \lfloor \frac {n + 1} {2} \rfloor 个键),此时已经完成了所有的删除工作;

    • 根据观察可以发现,一般来说,叶子节点的父亲节点中的某一个键值和其右边的指针指向的叶子节点的第一个键值对的键是相等的;
    • 但是,如果删除的是叶子节点的第一个键值对,与之对应的父亲节点的键不修改不会影响到B+树的性质(有序);
  • 如果叶子节点删除一个键值对后,打破了B+树叶子节点的限制条件,有如下几种情况:

    • 如果该叶子节点是B+树中唯一的叶子节点,不需要任何的修改;

    • 如果该叶子节点存在兄弟节点,且其兄弟节点的键值对足够多,那么可以从其兄弟节点的键值对中拿一个过来,具体来说,

      • 如果该叶子节点的左兄弟节点的键值对数量大于 \lfloor \frac {n + 1} {2} \rfloor,那么把其左兄弟节点的最后一个键值对拿过来插入到该叶子节点的第一个键值对的位置上,并修改该叶子节点的父亲节点对应的键的大小(如果不修改,会破坏B+树有序的性质);
      • 如果该叶子节点的右兄弟节点的键值对数量大于 \lfloor \frac {n+1} {2} \rfloor,那么把其右兄弟节点的第一个键值对插入到该叶子节点的最后一个位置上,并修改其右兄弟叶子节点的父亲节点对应的键的大小(同理);
    • 如果不存在兄弟节点的键值对的数量符合大小要求,那么可以将该叶子节点和其兄弟节点合并;合并两个叶子节点,首线将两个叶子节点上的键值对放到一个叶子节点上,被删除的叶子节点在其父亲节点上对应有一个键(该键的大小为被删除的叶子节点的第一个键值对的键),该键和其右边的指针(指向被删除的叶子节点)也应该被删除;

      • 如果该键和其右边的指针被删除后,其所在的内部节点满足B+树对内部节点的要求,那么删除的工作就到此为止了;
      • 否则,类似叶子节点,根据不同的情况有类似的解决方案;
        • 如果该内部节点是根节点,那么也没有后序的处理了;
        • 如果其兄弟节点的键数量足够多,那么可以将其兄弟节点的键拿过来;具体来说(和叶子节点不同),假设当前内部节点为 v_i,目标是从其右兄弟 v_{i+1} 拿一个键过来,而且,两个节点的父亲节点中存在一个键 k,其左右指针分别指向 v_iv_{i+1},首先将键 k 插入到 v_i 上,然后把 v_{i+1} 的第一个键拿出来放入到 k 之前所在的位置,此时键的放置已经处理好了,但是还有一个指针没有放置(v_{i+1}的第一个键的左指针),将它放置到现在的k对应的右指针的位置上即可;从左兄弟节点拿键放置到该节点的方法同理;
        • 否则,需要合并两个兄弟内部节点;具体来说(和叶子节点不同),同理假设合并的内部节点分别为 v_iv_{i+1},他们的父亲节点上对应的键 k,合并时需要在父亲节点上删除键 k,在合并的叶子节点的对应位置上插入 k即可;由于两个被合并的兄弟节点的父亲节点被删除了一个键,也需要对该父亲节点进行类似的对内部节点的判断及操作;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,188评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,464评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,562评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,893评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,917评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,708评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,430评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,342评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,801评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,976评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,115评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,804评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,458评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,008评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,135评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,365评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,055评论 2 355

推荐阅读更多精彩内容