——本节内容为Bilibili王道考研《数据结构》P72~74视频内容笔记。
目录
一、B树的基本概念和性质
1.图示
2.定义
3.解释说明
4.B树的高度
二、B树的查找、插入与删除
1.B树的查找
2.B树的插入与删除
三、B+树
1. 基本概念
2.B树与B+树的区别
3.B+树的查找
4.B+树相对于B树的优势
如下图所示,这是一棵5叉B树:
B树又称多路平衡查找树,B树中所有结点的孩子个数的最大值称为B树的阶,通常用m表示。一棵m阶B树或为空树,或为满足如下特性的m叉树:
(1)树中每个结点至多有m棵子树,即至多含有m-1个关键字;
(2)若根结点不是终端结点,则至少有两棵子树;
(3)除根结点外的所有非叶节点至少有棵子树,即至少含有
个关键字;
(4)所有的叶结点都出现在同一层次上,并且不带信息(可以视为外部结点或类似于折半查找判定树的查找失败结点,实际上这些结点并不存在,指向这些结点的指针为空);
(5)所有的非叶节点的结构如下:
其中,Ki(i=1,2,...,n)为结点的关键字,且满足K1
以上为王道课本中所给出的B树的定义,下来我们再拿出刚才的5叉B树的图做例子来通俗易懂地来理解一下:
(1)图中的一个个灰色的框就是5叉B树的结点,这种结点的代码定义为:
struct Node{ //5叉B树的结点定义
ElemType keys[4]; //最多4个关键字
struct Node *child[5]; //最多5个孩子
int num; //结点中有几个关键字
};
可以看到,这种结点中可以存最多4个关键字(每个结点中的关键字有序:要么递增要么递减),而这4个关键字作为间隔(像图中那样),可以引申出5个指针来(将原本的“定义域”划分出多个区间),每个指针对应连接一个孩子结点,所以每个结点最多会有5棵子树。这也就是课本定义中的第(1)条。
(2)通过这些关键字,我们可以按照二叉查找树的查找规则,进行随机查找,这个规则应该不难理解。比如上面的5叉B树,我们要找13这个关键字:就要从根结点出发,先走22的左边指针到第二层第一个结点,依次和其中的关键字进行比较,找到13应该在的位置,不难看出应该是11的右边指针,所以到了右边指针所指的“第三层第三个”结点,依次比较然后找到13这个关键字(如果找14的话,就最终来到最下面的叶结点,也就是失败结点,此时查找失败)。所以我们要保证的是:每个关键字左边的指针所指的结点中的所有关键字都要小于该关键字,右边指针所指的结点中的所有关键字都要大于该关键字。这也就是课本定义中的第(5)条。
(3)来想一想,如果每个结点里的关键字个数很少的话,那么我们就需要更多的结点来存储这些关键字,然后就会导致整棵树变得很高,这时我们刚才所提到的查找操作的效率就会变得很低。所以为了保证查找效率,B树规定:
①根结点至少有两棵子树,即1个关键字;
②非根结点都必须至少有棵子树,即
个关键字;
这也就是课本定义中的第(3)条,说白了就是B树的规矩。
(4)还有一点,如果这棵树不够“平衡”的话,这棵树也会变得很高,也会降低查找效率。所以还要规定对于任何一个结点,其所有子树的高度都要相同,也就是要做到绝对的平衡,和满二叉树的结构类似。
(5)再来看看叶结点。这里所说的叶结点是图中的紫色结点,是查找失败的结点,其并不存在,指针指NULL。而像叶结点那一层的上一层称为终端结点。由于我们要做到“绝对的平衡”,所以所有的叶结点都会出现在同一层上,也就是课本定义中的第(4)条。
(6)最后来看第(2)条,如果这是一棵空的B树,那根结点就是终端结点,此时根结点没有子树;一旦有了第二层,根结点就会产生子树,有几棵呢?刚才提到根结点至少有2棵子树。
(1)大部分学校考试中算B树的高度,不包括叶结点(失败结点);
(2)含n个关键字的m阶B树,
①最小高度:即让每个结点尽可能的满,有m-1个关键字,m棵子树。则有,解出
;
②最大高度:即让各层的子树尽可能的少,根结点只能有两棵子树,其他结点只有棵子树。则第h+1层(即失败结点层)共有
个叶结点,n个关键字的B树必有n+1个叶子结点,则
,即
。
这两个公式的推导不予详细证明。
B树的查找和二叉查找树类似,进行关键字的大小比较,小的在根结点的左子树上找,大的在根结点的右子树上找。
(1)定位:利用查找的方法,找出插入该关键字的最底层中的某个非叶节点。
(2)插入:
①插入后的结点关键字个数小于m,可以直接插入,插入后必须检查被插入结点内的关键字的个数,如果不大于m-1时则插入成功;否则则需要进行结点的分裂。
②分裂规则:例如一棵5阶B树,如果在一个已经有4个关键字的结点内插入一个新元素,此时关键字数将要大于5阶B树的关键字上限值4。则进行如下分裂:取位置的关键字为中间位置,将整个结点分为两半,左半边的关键字留在原结点不动,右半边的关键字分裂出去,形成一个新的结点且其父结点也为原结点的孩子,最后将中间位置的关键字放入原结点的父结点中。
如果“中间位置的关键字放入原结点的父结点”这一操作导致了父结点的关键字个数超出上限值,则对父结点进行相同的分裂操作,直至这个过程传到根结点为止,进而将导致B树的高度增1。
(3)删除:
①直接删除:当被删除关键字所在结点的关键字个数大于等于时,表明删除关键字后仍满足B树的定义,则直接删除该关键字即可。
②“兄弟够借”:当删除后导致该结点的关键字个数低于下限值时,先看兄弟结点够不够“借”。即当(左/右)兄弟结点的关键字个数大于等于时,将兄弟结点中的一个关键字顶替对应的父结点,将父结点放入被删除结点中(该关键字的选取原则是交换顺序后要保证满足B树的性质)。
③“兄弟不够借”:当兄弟结点的关键字个数等于-1时,需要将关键字删除后与兄弟结点及双亲结点中的关键字进行合并。合并规则为:先将被删除关键字所在结点的剩余元素与兄弟结点的元素和处于他们两个结点中间的父结点关键字合并为一个结点,该结点的位置就是被删除关键字所在结点的位置。如果该操作导致父结点关键字个数低于下限值,则对父结点进行相同操作;如果导致根结点关键字减至0,则删除根结点即可。
(1)B+树要满足以下几个条件:
①每个分支结点最多有m棵子树;
②非叶的根结点至少有两棵子树,其他每个分支结点至少有棵子树;(不能出现根结点只有左子树或只有右子树的情况,这也是为了追求“绝对平衡”)
③结点的子树个数与关键字个数相等;
④所有的叶结点包含全部关键字及指向相应记录的指针,叶结点中将关键字按大小顺序排列,并且相邻叶结点按大小顺序相互链接起来;
⑤所有分支结点(可视为索引的索引)中仅包含它的各个子结点中关键字的最大值及指向其子结点的指针。
B+树的查找过程中,非叶结点上的关键字值等于给定值时并不终止查找,而是继续向下查找,直到查找到叶结点上的该关键字为止。所以在B+树中查找时,无论查找成功与否,每次查找都是一条从根结点到叶结点的路径。
在B+树中,非叶结点不含有该关键字对应记录的存储地址。这么做可以使一个磁盘块可以包含更多个关键字(磁盘块的大小是固定的),使得B+树的阶更大,树高更矮,读取磁盘的的次数更少,查找就会变得更快。