一、B树性质
1、B树简介
- B树是一种平衡的
多路
搜索树,多用于文件系统与数据库方面 - B树特性:
- 一个节点可以存储超过2个元素,可以拥有超过2个子节点
- 每个节点的
平衡因子
都为1
- B树命名:如上图的
5阶
B树,因为最多有5个子节点所以命名5阶
B树
2、m阶B树的性质(m >= 2)
- 假设一个节点存储的元素个数为
x
-
根节点储存
元素
个数:1 <= x <= (m - 1)
例如:3阶B树根节点个数为1 ~ 2
-
非根节储存
元素
个数:⌈(m / 2)⌉ - 1 <= x <= (m - 1)
(⌈⌉:表示向上取整) -
某节点的子节点,则子节点的个数
y = x + 1
- 根节点的子节点个数:
2 <= y <= m
- 非根节点的子节点个数:
⌈(m / 2)⌉ <= x <= m
- 根节点的子节点个数:
-
3、B树与二叉搜索树
-
将
二叉搜索树
的节点合并,可以成为B树 -
多代节点
合并,可以获得一个超级节点
2代
合并,最多拥有4
个子节点(至多为4阶B树
)3代
合并,最多拥有8
个子节点(至多为8阶B树
)n代
合并,最多拥有2^n
个子节点(至多为2^n阶B树
)
-
将
18
和33
合并,23
和30
合并,20
和21
合并,45
和47
合并,50
和52
合并。即将一个B树
变为二叉搜索树
二、B树的相关操作
1、搜索
- 先在节点内部
从小到大
搜索元素 - 如果命中,搜索结束
- 如果未命中,再去对应的
子节点
中搜索元素,重复步骤1
假设搜索72
,首先在根节点
做比较,72
大于40
,所以接着在根节点
的右子树
搜索,72
大于60
小于80
,继续在60
和80
之间的子树寻找,因为72
大于70
,所以需要继续往70
的右子树
寻找,但是右子树
为空,所以得出结论72
不在该B树
上
2、添加
- 新添加的元素必定是
叶子节点
- 假设插入
55
,首先在根节点
做比较,55
大于40
,所以接着在根节点
的右子树
搜索,55
小于60
,继续在60
的左子树
寻找,55
大于50
,所以将55
插入在节点50
的右侧
3、上溢(overflow)
- 假设上图一颗
4阶B树
,我们此时要插入98,如果直接添加在95-100之间- 最右下角的叶子节点的元素个数将超过限制
- 这种现象可以称之为:
上溢
4、上溢的解决
- 假设我们是在向
5阶B树
(每个节点最多包含4个元素)添加元素
- 上溢节点的元素个数必然等于
m(5)
- 假设上溢节点最
中间元素
的位置为k(3)
- 将
k(3)
位置的元素向上
与父节点合并
- 将
[0,k-1]
和[k+1,m-1]
位置的元素分裂成2
个子节点
,这2
个子节点的元素个数,必然都不会低于最低限制⌈(m / 2)⌉ - 1
- 一次分裂完毕后,有可能导致
父节点上溢
,依然按照上述方法解决
- 最极端的情况,有可能一致分裂到
根节点
- 添加元素导致的上溢,是唯一一种可能导致B树
长高
的操作
Demo:添加导致上溢
- 操作基于
4阶B树
- 插入
98
98
大于根节点
,继续往根节点
右子树比较,98
大于60
和80
,继续往80
右子树比较,98
大于90
,95
,小于100
,所以将98
插入在95
和100
中间。- 插入
98
之后,90 95 98 100
节点溢出,需要上溢
,将中间元素95或98
向上与父节点合并
,将90,98,100
节点分裂成2
个子节点 - 插入
52
- 插入
54
(注意此时的双重上溢)
5、删除
-
如果
删除
元素在叶子节点
中,那么直接删除
即可 -
删除
30
-
删除
的节点元素在非叶子节点
中- 先找到前驱或后继元素,
覆盖
所需要删除元素的值 - 再把前驱或后继元素删除
- 先找到前驱或后继元素,
-
删除
60
-
60
的前驱为55
,将55
从54和55
节点中删除,并将55
覆盖60
-
非叶子节点
的前驱或后继元素,必定在叶子节点
中- 所以这里的删除前驱或后继元素,就是最开始提到的情况:删除的元素在叶子节点中
- 真正的删除元素都发生在叶子节点中
6 、下溢(underflow)
- 假设一颗
5阶B树
,删除22
- 叶子节点被删除一个元素后,元素个数可能会低于最低限制
⌈(m / 2)⌉ - 1
- 这种现象称为:
下溢(underflow)
7、下溢的解决
-
下溢节点的元素数量必然等于
⌈(m / 2)⌉ -2
-
如果下溢节点临近的
兄弟节点
,有至少⌈(m / 2)⌉
个元素,可以向其借一个元素 -
绿色节点在删除一个元素后,节点元素个数低于最低限制
⌈(m / 2)⌉ - 1
- 为了使树继续满足B树的要求,需要对绿色节点进行
下溢
操作 - 将父节点的元素
b
插入到下溢节点的0
位置(最小位置) - 用兄弟节点的元素
a
(最大的元素)替代父节点的元素b
- 这种操作其实就是:
旋转
- 注意子节点
d
也需要调整
- 为了使树继续满足B树的要求,需要对绿色节点进行
-
如果下溢节点临近的兄弟节点,只有
⌈(m / 2)⌉ - 1
个元素- 将父节点的元素b挪下来跟左右子节点进行
合并
- 合并后的节点元素个数等于
⌈(m / 2)⌉ + ⌈(m / 2)⌉ - 2
,不超过m - 1
- 这个操作可能会导致父节点下溢,依然按照上述方法解决,下溢现象可能会一直往上传播
- 添加元素导致的下溢,是唯一可能导致B树
变矮
的操作
- 将父节点的元素b挪下来跟左右子节点进行