B树概述
概述
1. 为什么要引入B树
有前面的学习可知,BST、AVL、RBT(二叉树)基本都可以把查询的复杂度控制在O(logN)左右,但是,上述的几种树均存储在内存(往往小于磁盘容量)中,不适合大量数据的存储。
B树(又称B-树),结合存储方式(存储在磁盘上)以及树的特性,适合存储数据库等有大量数据元素的情况。
- 二叉树:找一个节点,在内存上一个内存周期(内存速度慢 )。
- B树:找一个节点,在磁盘上存储一个磁盘周期(磁盘速度慢)。
由此又引出一个新的问题,虽然存储在磁盘上又很大的存储空间,但是二叉树每多一层,在磁盘上查找的时间延迟就会增加很多,因此我们需要设计出一种尽量“胖”的树,来降低树的高度,实现既能存储大量数据,又能较快进行查找的结构,于是引入了B树。
相当于一个N叉树(多路查找树):每一层存放尽量多的节点
磁盘概念补充:(留个坑以后补)
2.B树/B-树的定义
B-树,又称多了平衡查找树,B树中所有结点的孩子个数的最大值称为B树的阶,通常用m表示,当m=2时,就是常见的二叉搜索树。
一棵m阶的B树定义如下
- 每个节点最多有m-1个关键字;
- 根节点最少可以只有1个关键字;
- 非根节点至少有ceil(m/2)-1个关键字;
- 每个节点中的关键字都按照从小到大的顺序排列,每个关键字的左子树的所有关键字都小于它,所有右子树中的关键字都大于它。
- 所有叶子节点都位于同一层,或者说根节点到每个叶子节点的长度相同。
3.B树的查找
与BST(二叉排序树)相似,只不过B树的每个节点包含多个关键字,从根结点开始,从上往下递归的遍历树。在每一层节点上,使用二分查找法匹配目标键,或者通过值得范围来确定子树。
插入
1.回溯插入法
先通过上面的查找定位操作定位到一个查找失败的节点,然后检查该节点的父节点的关键字个数,若是关键字个数小于m-1,那么说明可以直接插入到改节点(叶子节点),否则的话插入后会引起节点的分裂
-
去一个新节点,在插入key后的原节点中,从中间位置ceil(m/2)将其中的关键字分为两部分。
-
左部分包含的关键字放在原节点中,右部分包含的关键字放到新节点中,中间位置ceil(m/2)的节点插入原节点的父节点。
-
若此时导致其父节点的关键字个数也超过了上线,则继续这种分裂操作。直到这个过程传到根节点为止,当让B-Tree的高度也增加。
-
回溯插入法案例(m=2)

2.主动插入法
主动插入法流程
- 初始化x作为根节点
- 当x不是叶子节点,执行如下操作
- 找到 x 的下一个要被访问的孩子节点 y
- 如果 y 没有满,则将节点 y 作为作为新的 x
- 如果 y 已经满了,拆分 y ,节点 x 的指针指向节点 y 的两部分。如果 k 比 y 中间的关键字小,则将 y 的第一部分作为新的 x ,否则将 y 的第二部分作为新的 x ,当将 y 拆分后,将 y 中的一个关键字移动到它的父节点 x 当中。
- 当 x 是叶子节点时,第二部结束;由于我们已经提前拆分了所有节点,x 必定至少有一个额外的关键字空间,进行简单插入即可。
B-树的插入操作是一种主动插入算法,因为在插入新的关键字之前,我们会将所有已满的节点进行拆分,提前拆分的好处就是,我们不必进行回溯,遍历节点两次。如果我们不事先拆分一个已满的节点,而仅仅在插入新的关键字时才拆分它,那么最终可能需要再次从根节点出发遍历所有节点,比如我们在到达叶子节点时,将叶子节点进行拆分,并将其中的一个关键字上移导致父节点分裂(因为上移导致父节点超出可存储的关键字个数),父节点分裂后,新的关键字继续上移,将可能导致新的父节点弗列,从而出现大量的回溯操作。但是B-树这种主动插入算法中就不会出现级联效应。当然这种主动插入的缺点也很明显,我们可能进行很多不必要的拆分操作。
删除
B-树的删除就复杂的多了,分为下面几种情况:
- 删除叶子节点中的元素
- 搜索要删除的元素
- 如果它在叶子节点上,直接将其删除
- 如果删除后产生了下溢出(键数小于最小值,当前层节点太少)。即将其父节点元素下移至当前节点,将兄弟节点中元素上移至父节点(若是左节点,上移最大节点;若是右节点,上移最小元素)
- 若兄弟节点也达到下限,则合并兄弟节点与分割键。
- 删除内部节点中的元素
- 内部节点中元素为其左右子节点的分割值,需要从左子节点最大元素或右子节点最小元素中选一个新的分割符。被选中的分割符从原子节点中移除,作为新的分割值替换掉被删除的节点
- 上一步中,若左右节点元素均达到下限,则合并左右子节点
- 若删除元素后,其中节点元素的数量小于下限值,则继续合并。
总结来说:删除后若该处节点的键数小于下限值,则从其他节点中补齐,如果把其他节点的节点移过来会导致其他节点的键数也小于下限值那么就采用合并的方法。将父节点中的一个和兄弟节点合并。
B+树概述
B+树是在 B树 的基础上改进的版本,数据库索引几乎都用它。
[30 | 60]
/ | \
[10 20 30] [40 50 60] [70 80 90]
↘ ↘ ↘
(链表连接)----(链表连接)----(链表连接)
B+ 树的特点
- 非叶子节点只存键(key),不存数据(value)。
→ 数据都放在叶子节点中。 - 所有叶子节点通过链表相连。
→ 方便顺序遍历、范围查询。 - 查找路径更稳定:所有数据都在同一层。
通俗比喻:
B+树就像图书馆的目录卡:上面每层只是“指路的目录”,真正的书(数据)都放在最底层的书架(叶子节点),而且书架还用链子(链表)串起来,方便连续找书。

被折叠的 条评论
为什么被折叠?



