b树 java_B树的插入 - EillenMe的个人空间 - OSCHINA - 中文开源技术交流社区

这两天一直在看B树,现在终于搞清楚一点点了。特写下博客,加深理解

1、B树的插入:

分析:在二叉查找树中,关键字的插入都是在叶子结点中。但是在B树中,不能简单地创建一个新的叶子结点,然后将其插入,因为这样得到的树不再是一棵有效的B树。相反的,我们将新的关键字插入到一个已经存在的叶子结点上。但这样又会带来一个问题:如果插入前此叶节点已经是一个满叶节点,故要引入一个操作,将一个满的节点y(有2t-1个关键字)按其中间关键字key(t)[y]分裂成两个各含t-1个关键字的节点。中间关键字被提升到y的父节点上,以标识两棵新的子节点的划分。但是,如果y的双亲也是满节点,则它必须在新插入关键字之前进行分裂(注意,满结点的分裂动作会沿着树向上传播)。

为解决回朔问题:我们在沿着树往下查找新关键字的插入位置时,就将沿途遇到的每个满结点(包括叶节点本身)进行分裂。因此,每当要分裂一个满结点y时,就能保证它的双亲结点不是满的。

1.1满结点的分裂:

f0d4a637631e152e01fb9a2565b09520.png

其中分裂前 :

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);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值