完整教程:超详细图解 B 树:从原理到插入删除,手把手构造全过程
超详细图解 B 树:从原理到插入删除,手把手构造全过程
B 树不是二叉树,却比红黑树更“稳”——它是数据库和文件系统的幕后英雄。
如果你用过 MySQL、MongoDB 或 Linux 文件系统,那你一定间接用过 B 树(B-Tree)。它不像红黑树那样常出现在算法题里,却是大规模数据存储的核心结构。
今天,我们就来彻底讲清楚:
什么是 B 树?
它为什么能高效支持磁盘 I/O?
插入和删除时到底发生了什么?
每一种边界情况,都配 ASCII 图示 + 例子!
文末还有 从空树开始,一步步构造完整 B 树的全过程
一、B 树是什么?为什么需要它?
✅ 基本定义(以 m 阶 B 树为例):
一棵 m 阶 B 树 满足以下性质:
每个结点最多有 m - 1 个关键字,最多 m 个子树;
除根结点外,每个内部结点至少有 ⌈m/2⌉ - 1 个关键字;
根结点至少有 1 个关键字(除非树为空);
所有叶子结点在同一层(完美平衡);
结点内关键字有序,子树按区间划分。
举个例子:5 阶 B 树 → 每个结点最多 4 个关键字,非根最少 2 个。
为什么 B 树适合磁盘存储?
磁盘读写以“块”为单位(如 4KB)
B 树高度低、分支多,一次 I/O 可读取大量关键字
相比二叉树(高度 ≈ log₂N),B 树高度 ≈ logₘN(m 很大,如 100+)
二、B 树的插入操作:分裂是关键!
插入总是发生在叶子结点。如果插入后关键字数 > m−1,就分裂。
我们以 5 阶 B 树(m=5)为例:
最多 4 个关键字
分裂时:5 个关键字 → 上提第 3 个(⌈5/2⌉ = 3)
✅ 情况 1:插入后未溢出 → 直接插入
当前结点:
[10, 20, 30]
插入 25 → 排序后:
[10, 20, 25, 30] ← 4个,合法
✅ 无需分裂。
✅ 情况 2:叶子溢出,父结点有空间
当前树:
[50]
/ \
[10,20,25,30] [60,70]
插入 40 到左子树 → 左子变成 [10,20,25,30,40](5个,溢出!)
分裂左子树:
关键字:
[10,20,25,30,40]上提第 3 个:25
左新:
[10,20],右新:[30,40]
更新后树:
[25, 50]
/ | \
[10,20] [30,40] [60,70]
✅ 父结点原为 [50],插入 25 后变成 [25,50](2个 ≤ 4),合法!
✅ 情况 3:连锁分裂(向上传播)
当前树(父结点已满):
[20,30,40,50]
/ / | \ \
[10] [25] [35] [45] [55,60]
在最左子树连续插入 6,7,8,9,10 后,左子变为 [6,7,8,9,10](溢出)
→ 分裂左子,上提 8
→ 父结点变成 [8,20,30,40,50](5个,也溢出!)
→ 再分裂父结点,上提 30
→ 创建新根
最终树:
[30]
/ \
[8,20] [40,50]
/ | \ / | \
[6,7][9,10][25][35][45][55,60]
✅ 树高从 2 增加到 3!
三、B 树的删除操作:比插入更复杂!
删除可能发生在内部或叶子结点。核心目标:保持关键字数 ≥ 下限(5阶中为2)。
✅ 情况 1:直接删除(仍 ≥ 下限)
结点:[10,20,30,40]
删除 30 → [10,20,40](3 ≥ 2)→ ✅
✅ 情况 2:从兄弟“借位”
当前树:
[50]
/ \
[10,20,30] [60,70,80,90]
删除 30 → 左子 [10,20](合法)
再删 20 → [10],可借:
父 50 下移
右兄弟最小 60 上移
左子变成
[10,50]右子变成
[70,80,90]
新树:
[60]
/ \
[10,50] [70,80,90]
✅ 两边都 ≥2!
✅ 情况 3:合并(兄弟也穷)
当前树:
[50]
/ \
[10] [60]
删除 10 → 左子空(0 < 2)
右兄弟只有 1 个(<2),无法借 → 合并!
合并步骤:
把父结点 50 拿下来
合并左右子 + 50 →
[10,50,60]父结点变空 → 删除父结点
结果:
[10,50,60]
✅ 树高降低!
✅ 情况 4:删除内部结点
树:
[30]
/ \
[10,20] [40,50]
要删除 30(内部结点)
→ 用后继 40 替换它
→ 在右子树中删除 40 → 右子变 [50](1 < 2)
兄弟 [10,20] 刚好下限,无法借 → 合并
合并后:
[10,20,40,50]
✅ 完成!
四、完整构造演示:从空树插入 10 个数
目标:5 阶 B 树,插入序列:3, 7, 1, 8, 5, 10, 2, 9, 4, 6
Step 1–4:直接插入
[1,3,7,8]
Step 5:插入 5 → 溢出,分裂
[5]
/ \
[1,3] [7,8]
Step 6–8:插入 10,2,9
[5]
/ \
[1,2,3] [7,8,9,10]
Step 9:插入 4 → 左子满但未溢出
[5]
/ \
[1,2,3,4] [7,8,9,10]
Step 10:插入 6 → 右子溢出,分裂
右子变为 [6,7,8,9,10] → 上提 8
最终树:
[5,8]
/ | \
[1,2,3,4] [6,7] [9,10]
✅ 所有结点关键字数合法,树高为 2!
结语
B 树的美,在于它的自平衡机制:
插入 → 分裂 → 向上传播
删除 → 借位/合并 → 向上传播
每一步都像搭积木,稳而不乱。
下次你看到数据库索引飞快查询百万数据,就知道——那是 B 树在默默分裂与合并。
动手建议:用纸笔模拟一遍上述构造过程,你会对 B 树有质的飞跃!
❤️ 如果你觉得这篇推文帮你真正理解了 B 树,欢迎 点赞、在看、转发!
评论区留下你的疑问,我们一起拆解数据结构!
浙公网安备 33010602011771号