B
树
二叉树
满二叉树是高度为 h 的且有 2h−12^h - 12h−1 个节点的二叉树
完全二叉树是高为 hhh,有 nnn 个节点,当且仅当其每个节点都与高为 hhh 的满二叉树中编号为 1−n1-n1−n 的节点一一对应
二叉排序树(二叉查找树,Binary sort tree, Binary search tree),是一个空树或者非空树,当为非空树时,满足以下三个条件:
- 当左子树非空时,则左子树上所有的节点值小于根节点
- 当右子树非空时,则右子树上所有的节点值大于根节点(不会出现相同的值)
- 左、右子树本身也是一颗二叉排序树
平衡二叉树(AVL),任意节点的平衡因子的绝对值不超过 111
平衡因子=左子树的高度−右子树的高度平衡因子 = 左子树的高度 - 右子树的高度平衡因子=左子树的高度−右子树的高度
高度为 hhh 的最小(节点数量最少)平衡二叉树的节点数为 NhN_hNh
Nh=Nh−1+Nh−2+1N_h = N_{h-1} + N_{h-2} + 1Nh=Nh−1+Nh−2+1
其中,N0=0N_0 = 0N0=0 并且 N1=1N_1 = 1N1=1
所以,N2=2N_2 = 2N2=2,N3=4N_3 = 4N3=4,N4=7N_4 = 7N4=7,N5=12N_5 = 12N5=12,N6=20N_6 = 20N6=20
在二叉树中,每个节点有数据项,最多有两个子节点。如果允许每个节点可以有更多的数据项和更多的子节点,就是多叉树(multiway tree)
多叉树通过重新组织节点,减少了树的高度,能够对二叉树进行优化
B
树
B
树,又称 多路平衡查找树,B
树中所有节点的孩子节点数的最大值称为 B
树的阶
B
树是一种自平衡的树,根节点到其叶子节点的路径高度都是一样的,能够保持数据有序(通过中序遍历能得到有序数据)
一棵 mmm 阶 B
树或为空树,或为满足如下特性的 mmm 叉树:
-
树中每个节点至多有 mmm 棵子树(即至多含有 m−1m-1m−1 个关键字)
-
若根节点不是终端节点,则至少有两棵子树
-
除根节点外的所有非叶节点至少有 ⌈m/2⌉\lceil m/2 \rceil⌈m/2⌉ 棵子树,(即 ⌈m/2⌉−1\lceil m/2 \rceil - 1⌈m/2⌉−1 个关键字)
-
非叶节点的结构:
Ki(i=1,2,...,n)为节点的关键字,K1<K2<...<KnK_i (i = 1, 2, ..., n) 为节点的关键字,K_1 < K_2 < ... < K_nKi(i=1,2,...,n)为节点的关键字,K1<K2<...<Kn
Pi(i=0,1,...,n)为子树根节点的指针,P_i (i = 0, 1, ..., n) 为子树根节点的指针,Pi(i=0,1,...,n)为子树根节点的指针,
Pi−1P_{i - 1}Pi−1 所指子树的关键字均小于Ki,所指子树的关键字均小于 K_i,所指子树的关键字均小于Ki,
PiP_iPi 所指子树的关键字均大于Ki所指子树的关键字均大于 K_i所指子树的关键字均大于Ki
-
所有的叶节点都出现在同一层次上,并不带任何信息
2-3 树是最简单的 B
树结构, 具有如下特点:
- 2-3 树的所有叶子节点都在同一层.(只要是
B
树都满足这个条件) - 有两个子节点的节点叫二节点,二节点要么没有子节点,要么有两个子节点.
- 有三个子节点的节点叫三节点,三节点要么没有子节点,要么有三个子节点.
- 2-3 树是由二节点和三节点构成的树。
2-3-4 树也是 B
树的一种,由以下节点组成:
- 2-节点,含有一个元素(值或键值对)和两个子树(左右子树),左子树所有的值均小于父节点的值,右子树所有的值均大于父节点的值;
- 3-节点,含有两个元素和三个子树,左子树所有的值均小于父节点最小元素的值,中间子树所有的值均位于父节点两个元素之间,右子树所有的值均大于父节点最大元素的值;
- 4-节点,含有三个元素和四个子树,节点之间的比较也满足二分搜索树的性质
如下示例 B
树 :
nnn 个关键字,阶数为 mmm,高度为 hhh 的
B
树有:
B
树的相关操作
查找
- 在
B
树中找节点 (磁盘上) - 在节点中查找关键字 (内存上)
B
树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的子结点;重复,直到所对应的子指针为空,或已经是叶子结点
关键字集合分布在整颗树中, 即叶子节点和非叶子节点都存放数据.
搜索有可能在非叶子结点结束
其搜索性能等价于在关键字全集内做一次二分查找
插入
-
定位:
查找插入该关键字的位置,即最底层中的某个非叶子节点(规定一定是插入在最底层的某个非叶子节点内) -
插入:
若插入后,不会破坏 mmm 阶二叉树的定义,即插入后节点关键字个数在属于 [⌈m/2⌉−1,m−1][\lceil m/2 \rceil - 1, m - 1][⌈m/2⌉−1,m−1],则直接插入;
若插入后,关键字数量大于 m−1m - 1m−1,则对插入后的节点进行 分裂 操作;
分裂:
- 插入后的节点中间位置(⌈m/2⌉\lceil m/2 \rceil⌈m/2⌉)关键字并入父节点中,
- 中间节点左侧节点留在原先的节点中,右侧节点放入新的节点中,
- 若并入父节点后,父节点关键字数量超出范围,继续向上分裂,直到符合要求为止
删除
B
树中结点可以分为:终端结点和非终端结点,两种结点的删除是不一样的
对于终端结点:
-
直接删除:
若被删除关键字所在节点关键字总数 >⌈m/2⌉−1> \lceil m/2 \rceil - 1>⌈m/2⌉−1 ,表明,删除后仍满足
B
树定义,直接删除
-
兄弟够借
若被删除关键字所在节点关键字总数 =⌈m/2⌉−1= \lceil m/2 \rceil - 1=⌈m/2⌉−1,且与此节点邻近的兄弟节点的关键字个数 >⌈m/2⌉> \lceil m/2 \rceil>⌈m/2⌉,则需要从兄弟节点借一个关键字,此过程需要调整该节点、双亲节点和兄弟节点的关键字
-
兄弟不够借
若被删除关键字所在节点关键字总数 =⌈m/2⌉−1= \lceil m/2 \rceil - 1=⌈m/2⌉−1,且与此节点邻近的兄弟节点的关键字个数 =⌈m/2⌉−1= \lceil m/2 \rceil - 1=⌈m/2⌉−1,则删除关键字,并与一个不够借的兄弟节点和双亲节点中两兄弟子树中间的关键字合并
合并后若双亲节点因减少一个节点导致不符合定义,则继续执行 2、3 步骤
对于非终端结点:
-
若小于 kkk 的子树中关键字个数 >⌈m/2⌉−1> \lceil m/2 \rceil - 1>⌈m/2⌉−1,则找出 kkk 的前驱值 k′k^{'}k′,并用 k′k^{'}k′ 来取代 kkk,再递归地删除 k′k^{'}k′ 即可
-
若大于 kkk 的子树中关键字个数 >⌈m/2⌉−1> \lceil m/2 \rceil - 1>⌈m/2⌉−1,则找出 kkk 的前驱值 k′k^{'}k′,并用 k′k^{'}k′ 来取代 kkk,再递归地删除 k′k^{'}k′ 即可
-
若前后两子树关键字个数均为 ⌈m/2⌉−1\lceil m/2 \rceil - 1⌈m/2⌉−1,则直接两个子结点合并,然后删除 kkk 即可
B+
树
一棵 mmm 阶 B+
树满足如下特性:
-
每个分支结点至多有 mmm 棵子树(子结点)
-
若根节点不是终端节点,则至少有两棵子树
-
除根节点外的所有非叶节点至少有 ⌈m/2⌉\lceil m/2 \rceil⌈m/2⌉ 棵子树,子树和关键字个数相等
-
所有叶节点包含全部关键字以及指向相应记录的指针,叶节点中将关键字按大小顺序排列,并且相邻结点按大小顺序连接起来
-
所有分支结点(可视为索引的索引)中仅包含他的各个子结点(下一级索引块)中关键字的最大值以及指向其子结点的指针
相比B
树,B+
树更适合文件索引系统
B+
树与 B
树
- 在
B+
树中,具有 nnn 个关键字的结点值含有 nnn 棵子树,即每个关键字对应一棵子树;在B
树中,具有 nnn 个关键字的结点含有 n+1n + 1n+1 棵子树 - 在
B+
树中,叶节点包含信息,所有非叶结点仅起索引作用,非叶结点中的每个索引项只含有对应子树的最大关键字和指向该子树关键字的指针,不含有该关键字对应记录的存储地址 - 在
B+
树中,叶节点包含全部关键字,即在非叶节点中出现的关键字也会出现在叶节点中;在B
树中,叶节点包含的关键字和其他结点包含的关键字是不重复的
B+
树中的查找
B+
树中有两种查找方式:多路查找和顺序查找
在 B+
树中查找时,无论查找成功还是查找失败,一定是查找到叶节点当中的值为止
B+
树与索引
索引
索引: 以某种方式指向具体的数据的数据结构
索引的特点:
- 优点:可以加快数据的检索速度,提高数据库的性能
- 缺点1:索引也需要占据一定的物理空间
- 缺点2:当表中的数据进行增、删、改时,索引也需要维护,降低了数据的维护速度
B+
树索引
B+
树索引 是关系型数据库系统中最常用也最为高效的索引,是 B+
树在数据库中的实现
在数据库中,B+
树的高度一般是 2−42-42−4 层,也就是,查找某一键值对应的行记录只需要 2-4 次 IO
B+
树相比 B
树更适合做文件系统索引:
- 磁盘 IO 读写次数相比
B
树降低了 - 每次查询的时间复杂度是固定的
- 适合做范围查询,遍历效率更高
在InnoDB中 B+
树高度一般为2-3层,它就能满足千万级的数据存储
B+
树的存放总行记录数 = 根节点指针数 * 单个叶子记录的行数