搜索步骤

跟二叉搜索树的搜索类似

步骤1. 先在节点内部从小到大开始搜索元素
步骤2. 如果命中,搜索结束
步骤3. 如果未命中,再去对应的子节点中搜索元素,重复步骤 1

查找操作

在二叉树中,每个结点只有一个元素。但是在B-Tree中,每个结点都可能包含多个元素,并且非叶子结点在元素的左右都有指向子结点的指针。

如果需要查找一个元素,那流程是怎么样的呢?我们看下图,如果我们要在下面的B-Tree中找到关键字24,那流程如下

04.数据操作 - 图1
04.数据操作 - 图2
04.数据操作 - 图3
04.数据操作 - 图4

从这个流程我们能看出,B-Tree的查询效率好像也并不比平衡二叉树高。但是查询所经过的结点数量要少很多,也就意味着要少很多次的磁盘IO,这对 性能的提升是很大的。

插入操作

从已有的B树插入

新添加的元素必定是添加到叶子节点(就是最后一排),

image.png

插入详细步骤:
**

插入55
image.png

插入95
image.png

**
再插入 98 呢?(假设这是一棵 4阶B树)
最右下角的叶子节点的元素个数将超过限制
这种现象可以称之为:上溢(overflow)

添加上溢的解决

假如是五阶b树,那么一个节点最多四个元素.

1.上溢节点的元素个数必然等于 m
假如说是五阶b树,那么m就是5.

2.假设上溢节点最中间元素的位置为 k

假如说中间元素是34
image.png

3.将 k 位置的元素向上与父节点合并
image.png

4.将 [0, k-1] 和 [k + 1, m - 1] 位置的元素分裂成 2 个子节点

image.png
因为34和父节点合并了,所以以前和34节点平级的节点现在变成了34节点的子节点

一次分裂完毕后,有可能导致父节点上溢,父节点依然按照上述方法,从步骤2开始重新解决

最极端的情况,有可能一直分裂到根节点**

这 2 个子节点的元素个数,必然都不会低于最低限制(┌ m/2 ┐ − 1)
假如说m是5,那么就是子节点最少要存储2个元素
image.png

插入操作,上溢演示

原始b树:
image.png

插入 98:
95向上合并了.
image.png

插入52:
image.png

插入 54
54 插入之后52向上合并,成为52 60 80 95 , 然后60又向上合并,根节点成为40 60

image.png

从空的B树开始插入

B树特性

1、每个结点最多m个子结点。
2、除了根结点和叶子结点外,每个结点最少有m/2(向上取整)个子结点。
3、如果根结点不是叶子结点,那根结点至少包含两个子结点。
4、所有的叶子结点都位于同一层。
5、每个结点都包含k个元素(关键字),这里m/2≤k6、每个元素(关键字)字左结点的值,都小于或等于该元素(关键字)。右结点的值都大于或等于该元素(关键字)。

04.数据操作 - 图16
04.数据操作 - 图17
04.数据操作 - 图1804.数据操作 - 图19

B树的删除操作

真正的删除元素都是发生在叶子结点中.

假如需要删除的元素在叶子节点中,那么直接删除即可

假如需要删除的元素在叶子节点(最底层节点)中,那么直接删除即可

如果删除非叶子结点呢?

假如需要删除的元素在非叶子节点中
1.先找到前驱或后继元素,覆盖所需删除元素的值
再把前驱或后继元素删除

删除 60:

image.png

**
删除60,先找到60的前驱元素,就是55(通过52找的), 然后删除60,把55提出来覆盖掉原来60的位置

image.png

你发现了么,删除非叶子节点的数据, 真正被删掉的还是叶子节点的数据,就像上面的,你删除60,但是真正被删除的是原来55的位置.

删除下溢

叶子节点被删掉一个元素后,元素个数可能会低于最低限制( ≥ ┌ m/2 ┐ − 1 )
这种现象称为:下溢(underflow)

◼下溢节点的元素数量必然等于 ┌ m/2 ┐ − 2
◼如果下溢节点临近的兄弟节点,有至少 ┌ m/2 ┐ 个元素,可以向其借一个元素
将父节点的元素 b 插入到下溢节点的 0 位置(0位置就是最小位置)
image.png
用兄弟节点的元素 a(最大的元素)替代父节点的元素 b
image.png
这种操作其实就是:旋转,
将父节点挪到右分支子节点的左边, 将原来父节点左分支最大的a节点上升为父节点.

如果下溢节点临近的兄弟节点,只有 ┌ m/2 ┐ − 1 个元素
将父节点的元素 b(b是中间元素) 挪下来跟左右子节点进行合并. 左节点是蓝色的节点,右节点是绿色的节点
合并后的节点元素个数等于┌ m/2 ┐ + ┌ m/2 ┐ − 2,不超过 m − 1 ,不会出现上溢的情况.

image.png

结论:
说白了,就是一个节点如何产生下溢的话,就看看兄弟节点能不能借用一个,如果没有的话就父节点的中间元素拉下来向下合并就可以了

这个操作可能会导致父节点下溢,依然按照上述方法解决,下溢现象可能会一直往上传播