第九章 查找
9.2 动态查找表
三、B - 树
1.B-树的定义
B-树是一种 平衡 的 多路 查找 树:
多叉树的特性
在 m 阶的B-树上,每个非终端结点可能含有:
· n 个关键字 Ki(1≤ i≤n) n<m
· n 个指向记录的指针 Di(1≤i≤n)
· n+1 个指向子树的指针 Ai(0≤i≤n)
B-树结构的C语言描述如下:
typedef struct BTNode {
int keynum; // 结点中关键字个数,结点大小
struct BTNode *parent;
// 指向双亲结点的指针
KeyType key[m+1]; // 关键字(0号单元不用)
struct BTNode *ptr[m+1]; // 子树指针向量
Record *recptr[m+1]; // 记录指针向量
} BTNode, *BTree; // B树结点和B树的类型
查找树的特性
· 非叶结点中的多个关键字均自小至大有序排列,即:K1< K2 < … < Kn ;
· Ai-1 所指子树上所有关键字均小于Ki ;
· Ai 所指子树上所有关键字均大于Ki ;
平衡树的特性
· 树中所有结点均不带信息,且在树中的同一层次上;
· 若根结点不是叶子结点,则至少含有两棵子树;
· 其余所有含有非叶结点均至少含有[m/2]棵子树,至多含有m棵子树。
2.查找过程:
从根结点出发,沿指针搜索结点和在结点内进行顺序(或折半)查找 两个过程交叉进行。
若查找成功,则返回指向被查关键字所在结点的指针和关键字在结点中的位置;若查找不成功,则返回插入位置。
假设返回的是如下所述结构的记录:
typedef struct {
BTNode *pt; // 指向找到的结点的指针
int i; // 1..m,在结点中的关键字序号
int tag; // 标志查找成功(=1)或失败(=0)
} Result; // 在B树的查找结果类型
Result SearchBTree(BTree T, KeyType K) {
// 在m 阶的B-树 T 中查找关键字 K, 返回
// 查找结果 (pt, i, tag)。若查找成功,则
// 特征值 tag=1, 指针 pt 所指结点中第 i 个
// 关键字等于 K; 否则特征值 tag=0, 等于
// K 的关键字应插入在指针 pt 所指结点
// 中第 i 个关键字和第 i+1个关键字之间
} // SearchBTree
p=T; q=NULL; found=FALSE; i=0;
while (p && !found) {
n=p->keynum; i=Search(p, K);
// 在p->key[1..keynum]中查找 i , p->key[i]<=K<p->key[i+1]
if (i>0 && p->key[i]==K) found=TRUE;
else { q=p; p=p->ptr[i]; } // q 指示 p 的双亲
}
if (found) return (p,i,1); // 查找成功
else return (q,i,0); // 查找不成功
3.插入
在查找不成功之后,需进行插入。显然,关键字插入的位置必定在最下层的非叶结点,有下列几种情况:
1)插入后,该结点的关键字个数n<m, 不修改指针;
2)插入后,该结点的关键字个数 n=m,则需进行“结点分裂”,令 s = [m/2],在原结点中保留(A0,K1,…… , Ks-1,As-1);建新结点(As,Ks+1,…… ,Kn,An);将(Ks,p)插入双亲结点;
3)若双亲为空,则建新的根结点。
例如:下列为 3 阶B-树
插入关键字 = 60, 90,30,
4.删除
和插入的考虑相反,首先必须找到待删关键字所在结点,并且要求删除之后,结点中关键字的个数不能小于ém/2ù-1,否则,要从其左(或右)兄弟结点“借调”关键字,若其左和右兄弟结点均无关键字可借(结点中只有最少量的关键字),则必须进行结点的“合并”。有下列三种可能
1.被删关键字所在结点中的关键字数目不小于[m/2],则只需从该结点中删去该关键字Ki和相应指针Ai,树的其它部分不变。
删除关键字 = 12
2.被删关键字所在结点中的关键字数目等于ém/2ù-1,而与该结点相邻的右兄弟(或左兄弟)结点中的关键字数目大于ém/2ù-1,则需将其兄弟结点中的最小(或最大)关键字上移至双亲结点中,而将双亲结点中小于(或大于)且紧靠该上移关键字的关键字下移至被删结点中。
删除关键字 = 50
3.被删关键字所在结点和其相邻的兄弟结点中的关键字数目均等于ém/2ù-1,假设该结点有兄弟结点,且其右兄弟结点地址由双亲结点中的Ai所指,则在删去关键字之后,它所在结点中剩余的关键字和指针,加上双亲结点中的关键字Ki,合并到Ai所指兄弟结点中(若没有右兄弟,则合并至左兄弟结点中)。
删除关键字 = 53
5.查找性能的分析
在B-树中进行查找时,其查找时间主要花费在搜索结点(访问外存)上,即主要取决于B-树的深度。
问:含 N 个关键字的 m 阶 B-树可能达到的最大深度 H 为多少?
反过来问: 深度为H的B-树中,至少含有多少个结点?
先推导每一层所含最少结点数:
第 1 层 1 个
第 2 层 2 个
第 3 层 2*[m/2]个
第 4 层 2*([m/2])2 个
… …
第 H+1 层 2*([m/2]) H-1 个
结论:
在含 N 个关键字的 B-树上进行一次查找,需访问的结点个数不超过
四、B+树
1.B+树的结构特点:
※ 每个叶子结点中含有 n 个关键字和 n 个指向记录的指针;并且,所有叶子结点彼此相链接构成一个有序链表,其头指针指向含最小关键字的结点;
※ 每个非叶结点中的关键字 Ki 即为其相应指针 Ai 所指子树中关键字的最大值;
※ 所有叶子结点都处在同一层次上,每个叶子结点中关键字的个数均介于 ém/2ù和 m 之间。