B+树要点梳理
B+树重要操作
中间节点
- 中间节点的key,与其对应的指针的原则是,小于key的元素在其指针指向的节点中
- 中间节点的key可以看成是右斜着排放的,即小于等于key的节点由key对应的指针指定,最有一个指针指向大于最右侧key的节点
分裂
- 当中间节点数量满了时,进行分裂,新生成一个相邻的中间节点right_internal_node
- 计算原先保留多少元素, 例如保留left_count = K/2
- 将left_count对应的key作为upper_key后续插入到中间节点
- 从left_count + 1下标开始,将key复制到新生成的节点中
- 将left_count下表对应的指针留在左节点
- 将left_count +1 下表对应的指针开始复制到新生成的节点中
分裂后插入上层中间节点
- 经过分裂有三个重要元素:left_internal_node(也就是原先被分裂节点), right_internal_node(新生成的节点),upper_key
- 上层中间节点为upper_internal_node
- 注意原先upper_internal_node有一个old_key和old_ptr指针指向left_internal_node,这个old_key肯定是比upper_key大的
- 将(upper_key, left_internal_node)作为一对插入到upper_internal_node
- 将old_key对应的old_ptr改成指向right_internal_node

删除
借入数据
中间节点删除数据后,如果数量少于最低值K/2,那么它可以尝试从它的相邻节点借入数据。那么它的相邻节点在哪里呢?第一类相邻节点是与中间节点共享一个父节点的节点,很容易通过其父节点找到。第二类相邻节点,不与其共享一个父节点:想象一下当节点是父节点的最左边节点时,那么在其父节点下,它只有一个右侧相邻节点,这个时候它的左侧相邻节点不在其父节点下;当节点是父节点的最右边节点时,那么在其父节点下,它只有一个左侧相邻节点,这时候它的右侧相邻节点不在其父节点下,而在右侧树分支下。

- 注意第二类的借入在实现的时候也可以不考虑,只不过这样会过早的带来节点合并。
节点合并
当节点确实从左右都没有节点可以借入数据时,那么它就可以与左右节点合并了。正因为其左右节点也没有多的节点可以借,说明其左右节点不大于K/2,那么合并后节点节点数量是会小于K的。
节点合并,我们可以总是选择与其相同父节点下的相邻节点进行合并。节点合并后,需要使父节点删除掉被合并数据的节点(需要注意的是在实际操作中,我们可以选择被删除的节点最终保留下来,也可以选择相邻节点最终保留下来,这只是实现方式)。
降级
父节点删除某个子节点后,需要检查父节点的key数量是否满足K/2要求,如果父节点不满足,那么父节点也需要执行借入动作,如果父节点无法接入,那么就需要执行合并动作。并最终出发祖父节点的删除动作。整个流程会递归上去最终可能会到根节点,若根节点删除了数据,且一个key也没有了。那么就要将其子节点设置成新的root了(奇怪?没有key还有子节点?注意中间节点指针比key多一个,就是说没有key,也至少有一个指针)。
叶子节点
插入
分裂
- 当叶子节点数量满了时,进行分裂,新生成一个相邻sibling节点
- 计算原先保留多少元素, 例如保留left_count = K/2
- 将下标left_count开始的key移动到新生成的节点
- 将left_count对应的key作为upper_key后续插入到中间节点
- 将下标left_count开始的value移动到新生成的节点
分裂后插入上层中间节点
- 新分裂出的节点的第一个key为upper_key
- 如果叶子节点没有上层中间节点,那么就新建一个中间节点作为根节点,把原先叶子节点以及新分裂出的叶子节点直接插入到新的中间节点。同时将upper_key插入到新中间节点中。即它有1个key,两个指针。
- 如果有上层中间节点
- 首先将upper_key插入到中间节点
- 其次将新分裂出的节点指针也插入到中间节点,这里需要注意的是由于中间节点的指针数量比key数量多一个。所以指针插入的index要比upper_key插入的index大1

删除
- 删除后,尝试从其右侧的节点借数据,前提是右侧节点包含m/2 +1个元素
- 若节点(且该节点不是中间节点的最左侧节点)最左边一个元素被删除了,则需要更新中间对应的key
借入数据
借入数据的流程是简单的,与中间节点类似。找到其相邻节点并拿到数据。同样需要注意的是它的相邻节点也可能不在其父节点下。
节点合并
与中间节点的操作类似,找到相邻节点,拷贝数据。通知父节点删除一个节点即可。
要记录哪些指针
- 从B+树的定义上来看,至少每个叶子节点需要记录一个指向右侧相邻节点的指针
其他指针要不要记录呢?
- 节点是否要记录父节点指针?
- 中间节点是否要记录右侧节点的指针?
- 节点是否要记录其左侧节点的指针?
这个因设计实现而异了,记录更多的指针,那么在寻找定位的时候肯定更加容易,但是也带来了很多维护成本,这个在设计的时候做考量。
如何找到相邻的节点
相同父节点下的相邻节点
很容易,很自然,进行遍历就可以或者对key进行find或二分法(注意所有节点里面的key都是有序的)
非相同父节点下的相邻节点
- 最节点的方式是记录节点(包括中间节点)的左侧、右侧指针
另外一种方式,如果不想过多的记录指针,那么可以通过搜索回溯的方式来找目标节点到相邻节点。 某个最左侧中间节点为例:
- 从它开始往上回溯,当回溯到的节点不是其父节点的最左侧节点时,说明我们已经找到了共同祖先
- 然后从共同祖先中的左侧节点(对应下图1的左侧节点3)开始往下找其最右侧的子节点,当往下搜索的层数与向上回溯的层数相同时,我们就找到了目标节点的相邻节点。
- 最右侧中间节点的搜索过程是类似的。

例如想找到节点5的做相邻节点4,就往上回溯首先到1, 5是1的最左侧节点,则继续向上到2,1不是2的最左侧节点,所有2就是共同祖先了。1的左侧节点3往下,找到最右侧节点4, 4与5是相同层级的,那么就是5的相邻左节点了。
另外一个问题是如何进行回溯呢?一种实现方式是子节点记录父节点的指针;另一种实现方式是,记录搜索过程的搜索栈(即从根节点到叶子节点经过了哪些中间节点,记录到一个列表里面)。
B+树要点梳理的更多相关文章
- 安全测试 + 渗透测试 Xmind 要点梳理
从事测试工作多年,一直对安全测试充满神秘感.买了本书,闲来无事时翻看了解.发现书的开头提供的Xmind脑图挺有参考价值,所以做了次“搬运工”,提供给想接触了解安全测试/渗透测试的小伙伴. 安全测试要点 ...
- .NET Core表达式树的梳理
最近要重写公司自己开发的ORM框架:其中有一部分就是查询的动态表达式:于是对这方面的东西做了一个简单的梳理 官网的解释: 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 ...
- js知识梳理6:关于函数的要点梳理(2)(作用域链和闭包)
写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...
- js知识梳理5:关于函数的要点梳理(1)
写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...
- vuex知识要点梳理
该内容为个人总结,请勿喷. 欢迎各位大神前来指点.
- APP测试基本流程以及APP测试要点
APP测试流程梳理 APP测试要点梳理 链接:http://pan.baidu.com/s/1gfaEZ1x 密码:07yt 1 APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开 ...
- 优动漫PAINT画树教程
依次解析画树要点!让画树不再是难事~ 优动漫PAINT下载:http://wm.makeding.com/iclk/?zoneid=18597
- ClickHouse源码笔记5:聚合函数的源码再梳理
笔者在源码笔记1之中分析过ClickHouse的聚合函数的实现,但是对于各个接口函数的实际如何共同工作的源码,回头看并没有那么明晰,主要原因是没有结合Aggregator的类来一起分析聚合函数的是如果 ...
- [学习笔记]设计模式之Abstract Factory
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...
- [学习笔记]设计模式之Builder
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构.但是,工作一段时间之后,自己渐渐意识到,哪怕是自己 ...
随机推荐
- 记一次Nacos漏洞的复现 --> 身份认证绕过漏洞(QVD-2023-6271)
前记 端午前两天,遇到公司某客户的站点是Nacos,随后就是网上搜一波漏洞,搜到 QVD-2023-6271,故做以下记录 漏洞复现 漏洞描述 漏洞原理为开源服务管理平台 Nacos在默认配置下未对 ...
- CeiT:商汤提出结合CNN优势的高效ViT模型 | 2021 arxiv
论文提出CeiT混合网络,结合了CNN在提取低维特征方面的局部性优势以及Transformer在建立长距离依赖关系方面的优势.CeiT在ImageNet和各种下游任务中达到了SOTA,收敛速度更快,而 ...
- aspnetcore插件开发dll热加载 二
这一篇文章应该是个总结. 投简历的时候是不是有人问我有没有abp的开发经历,汗颜! 在各位大神的尝试及自己的总结下,还是实现了业务和主机服务分离,通过dll动态的加载卸载,控制器动态的删除添加. 项目 ...
- winfrom 程序自己删除自己
[DllImport("kernel32.dll")] public static extern uint WinExec(string lpCmdLine, uint uCmdS ...
- navicat 如何调整查询区域字体大小
Navicat是一套快速.可靠和全面的数据库管理工具,专门用于简化数据库管理和降低管理成本.Navicat图形界面直观,提供简便的管理方法,设计和操作MySQL.MariaDB.SQL Server. ...
- 6.20考试总结(NOIP模拟9)[斐波那契·数颜色·分组]
一旦你尝试过天空的味道,你就会永远向上仰望 T1 斐波那契 解题思路 题目传送门 \(70pts\)做法 这个做法比较暴力,考场上也是看到范围\(10^{12}\)后知道需要推式子,但是感觉自己太菜了 ...
- 异构数据源同步之数据同步 → DataX 使用细节
开心一刻 中午我妈微信给我消息 妈:儿子啊,妈电话欠费了,能帮妈充个话费吗 我:妈,我知道了,我帮你充 当我帮我妈把话费充好,正准备回微信的时候,我妈微信给我发消息了 妈:等会儿子,不用充了,刚刚有个 ...
- 【Java】JVM字节码分析
一.功能 1.工作原理 2.解释和运行 jvm本质上是运行在计算机上的程序,负责运行java字节码文件 对字节码文件中的指令,实时的解释成机器码,供计算机执行 3.内存管理 自动为对象.方法等分配内存 ...
- 代码审计——基础(JAVASE)
JAVASE 目录 JAVASE 基本语法 关键字 变量 作业1 作业完成 第一题:简单的介绍了java语言历史,优势.发展 第二题:特性:面向对象.跨平台.封装.继承.多态.抽象.扩展性.健壮性.垃 ...
- INFINI Labs 产品更新 | Easysearch 新增分词插件、Gateway 支持邮件发送等功能
INFINI Labs 产品又更新啦~,本次更新概要如下:Easysearch 新增了分词插件.优化了生命周期管理功能等:Gateway 新增 smtp 过滤器来支持邮件的发送,支持自动跳过因为异常关 ...