这两天一直在看B树,现在终于搞清楚一点点了。特写下博客,加深理解
1、B树的插入:
分析:在二叉查找树中,关键字的插入都是在叶子结点中。但是在B树中,不能简单地创建一个新的叶子结点,然后将其插入,因为这样得到的树不再是一棵有效的B树。相反的,我们将新的关键字插入到一个已经存在的叶子结点上。但这样又会带来一个问题:如果插入前此叶节点已经是一个满叶节点,故要引入一个操作,将一个满的节点y(有2t-1个关键字)按其中间关键字key(t)[y]分裂成两个各含t-1个关键字的节点。中间关键字被提升到y的父节点上,以标识两棵新的子节点的划分。但是,如果y的双亲也是满节点,则它必须在新插入关键字之前进行分裂(注意,满结点的分裂动作会沿着树向上传播)。
为解决回朔问题:我们在沿着树往下查找新关键字的插入位置时,就将沿途遇到的每个满结点(包括叶节点本身)进行分裂。因此,每当要分裂一个满结点y时,就能保证它的双亲结点不是满的。
1.1满结点的分裂:
其中分裂前 :
key(i-1)[X] == N
key(i)[X] == W
c(i)[x] = Y
分裂后:
key(i-1)[X] == N
key(i)[X] == S
key(i+1)[X] == W
c(i)[X] == Y
c(i+1)[X] == Z
1.2 对满结点进行分裂的伪代码:
/*
* @param x : 父节点
* @param i : 第i个满子女进行分裂
* @param y : 满子女
*/
BTree_Split_Child(x, i, y)
{
//分配新结点z
z = AllocNewNode();
n[x] = t-1;
leaf[z] = leaf[y]; //这句话我在写代码的时候就忘记了
//将y结点后t-1个关键字复制到z结点中
for j=1 -> t-1
do key(j)[z] = key(j+t)[y];
//如果y结点不是叶子结点,将后t个指针(子女)复制到z结点中
if(!leaf[y])
{
for j=1 -> t;
do c(j)[z] = c(j+t)[y];
}
//将父节点从i到n[x]的关键字后移
for j = n[x] to i
do key(j+1)[x] = key(j)[x];
//将父节点从i+1到n[x]+1的指针后移
for j =n[x]+1 to i+1;
do c(j+1)[x] = c(j)[x];
将父节点第i个关键字和第i+1个指针都重新赋值
key(i)[x] = key(t)[y];
c(i+1)[x] = z;
//改变三个结点的关键字数目
n[x] = n[x] +1;
n[y] = t-1;
//写磁盘的操作
DISK_WRITE(y);
DISK_WRITE(z);
DISK_WRITE(x);
}
1.3 将关键字key插入B树的伪代码:
BTree_Insert(root, key)
{
//如果根节点是满结点,就要对根节点进行分裂
if n[root] = 2t-1
{
s = AllocNewNode();
n[s] = 0;
c[1] = root;
leaf[s] = false; //不是叶子结点
m_root = s; //B树新的根,这也是B树高度增长的唯一的方式(这个我在写代码的时候就忘记了)
BTree_Split_Child(s,1,root);
BTree_Insert_NonFull(s, key); //保证插入树的根节点非满 }
else
BTree_Insert_NonFull(root, key); //保证插入树的根节点非满
}
通过调用BTree_Insert_NonFull将关键字k插入到以该非满的根节点为根的树中。BTree_Insert_NonFull在需要沿树向下递归,必要时调用BTree_Split_Child,在任何时刻保证它所递归处理的节点时非满的。
1.4 BTree_Split_Child过程的伪代码:
BTree_Split_Child(x, key)
{
//在此函数前,我们能够保证x指向的节点时一个非满的节点
int i = n[x];
if(leaf[x])
{
//找到插入的叶节点的位置
while i>=1 && key(i)[x]>key
{
key(i+1)[x] = key(i)[x];
i= i -1;
}
key(i+1)[x] = key;
}
else
{ //不是叶节点
while i >= 1 && key(i)[x]>key
{
i = i-1;
}
i = i+1; //则key必插在以c(i)[x]为根的子树中
//判断c(i)[x]子树的根节点是否为满结点
z = c(i)[x];
if n[z] == 2t-1
{
//分裂结点
BTree_Split_Child(x, i, z);
if key(i)[x] < key
then i == i+1
}
BTree_Insert_NonFull(c(i)[x], key);
}
}