树算法之 B 树
罗朝辉(http://blog.csdn.net/kesalin)
转载请注明出处
B树是一种被设计成专门存储在磁盘上的平衡查找树。因为磁盘的操作速度要大大慢于随机存取存储器,所以在分析B树的性能时,不仅要看动态集合操作花了多少计算时间,还要看执行了多少次磁盘存储操作。B树与红黑树(下一篇介绍)类似,但在降低磁盘I/O操作次数方面要更好一些。许多数据库系统就使用B树或B树的变形来存储信息,想象一下一棵每个节点包含1001个key的高度为2的B树能容纳多少数据啊,而在内存中我们只存储了一个节点,在需要的时候再从磁盘中读取所需的节点。
B树红黑树比较:
B树的节点有很多子女,从几个到几千,而红黑树只有左右两个;一棵含有n个节点的B树与红黑树的高度均为O(lgn),只不过B树的分支较多,因此高度一般要少于红黑树。
B树到底是怎样一棵树呢,下面来看定义:
1),每个节点有如下域:
A),keyNum,节点中存储的关键字的个数。
B),keyNum个以非降序次序排列的关键字key[0...keyNum-1];
C),isLeaf,判断是否是叶子节点还是内节点的标志。
2),每个内节点还包含keyNum+1个指向其子女的指针child[i](i>=0&&i<=keyNum)。
3),各个关键字key[i]对存储在各子树中的关键字范围加以分隔:即key[i]大于等于其左侧子树中的所有关键字,而小于等于其右侧子树中的所有关键字。
4),每个叶节点具有相同的深度,即均为树的高度h。
5)每一个节点能包含的关键字有一个上限和下限。这些界限可以用一个称作B树的最小度数的固定整数T>=2来表示。
A),每个非根的节点必须至少有T-1个关键字。每个非根的内节点至少有T个子女。如果树是非空的,则根节点至少包含一个关键字。
B),每个节点可包含至多2T-1个关键字。所以一个内节点至多有2T个子女。当一个节点正好有2T-1个关键字时,我们就说这个节点是满的。
T等于2 时的B树是最简单的。这时每个内节点有2个或3个或4个子女,这种B树也被称作为2-3-4树。当然在实际应用中T的取值比这个大得多。
下面我实现了T默认等于2的B树:
//
定义B树的最小度数
//
每个节点中关键字的最大数目BTree_N=2*BTree_T-1
#define
BTree_T2
#define
BTree_N(BTree_T*2-1)
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
struct
BTNode
{
intkeynum;//结点中关键字的个数,keynum<=BTree_N
intkey[BTree_N];//关键字向量为key[0..keynum-1]
BTNode*child[BTree_T*2];//孩子指针向量为child[0..keynum]
boolisLeaf;//是否是叶子节点的标志
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
typedefBTNode
*
BTree;
//
B树的类型
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_create(BTree
*
tree,
const
int
*
data,
int
length);
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_destory(BTree
*
tree);
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_insert(BTree
*
tree,
int
key);
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_remove(BTree
*
tree,
int
key);
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_print(BTreetree,
int
her
=
1
);
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
在B树tree中查找关键字key,
//
成功时返回找到的节点的地址及key在其中的位置*pos
//
失败时返回NULL及查找失败时扫描到的节点位置*pos
//
BTNode
*
BTree_search(
const
BTreetree,
int
key,
int
*
pos);
下面来看具体的接口实现:
#define
max(a,b)(((a)>(b))?(a):(b))
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
#defineDEBUG_TREE
#ifdefDEBUG_TREE
#define
debug_print(fmt,
)printf(fmt,##__VA_ARGS__)
#else
#define
debug_print(fmt,
)
#endif
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
模拟向磁盘写入节点
void
disk_write(BTNode
*
node)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
printf("向磁盘写入节点/n");
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
模拟从磁盘读取节点
void
disk_read(BTNode
**
node)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
printf("从磁盘读取节点/n");
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
按层次打印B树
void
BTree_print(BTreetree,
int
her)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
inti;
BTNode*node=tree;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node)
{
printf("第%d层,%dnode:",her,node->keynum);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<node->keynum;++i)
{
printf("%c",node->key[i]);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
printf("/n");
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
++her;
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<=node->keynum;i++)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->child[i])
{
BTree_print(node->child[i],her);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
else
{
printf("树为空。/n");
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
将非满的节点与其第index个满孩子节点合并
//
parent是一个非满的父节点
//
node是tree孩子表中下标为index的孩子节点,且是满的
void
BTree_split_child(BTNode
*
parent,
int
index,BTNode
*
node)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
assert(parent&&node);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//创建新节点,存储node中后半部分的数据
BTNode*newNode=(BTNode*)calloc(sizeof(BTNode),1);
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!newNode)
{
printf("Error!outofmemory!/n");
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
newNode->isLeaf=node->isLeaf;
newNode->keynum=BTree_T-1;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//拷贝node后半部分关键字
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<newNode->keynum;++i)
{
newNode->key[i]=node->key[BTree_T+i];
node->key[BTree_T+i]=0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//如果node不是叶子节点,拷贝node后半部分的孩子节点
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!node->isLeaf)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<BTree_T;i++)
{
newNode->child[i]=node->child[BTree_T+i];
node->child[BTree_T+i]=NULL;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//将node分裂出newNode之后,里面的数据减半
node->keynum=BTree_T-1;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//调整父节点
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=parent->keynum;i>index;--i)
{
parent->child[i+1]=parent->child[i];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
parent->child[index+1]=newNode;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=parent->keynum-1;i>=index;--i)
{
parent->key[i+1]=parent->key[i];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
parent->key[index]=node->key[BTree_T-1];
++parent->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//清除node中的中后部数据
//可以不处理,因为是通过keynum控制访问的
//for(i=BTree_T-1;i<BTree_N;++i){
//node->key[i]=0;
//node->child[i+1]=NULL;
//}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//写入磁盘
disk_write(parent);
disk_write(newNode);
disk_write(node);
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_insert_nonfull(BTNode
*
node,
int
key)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
assert(node);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//节点是叶子节点,直接插入
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->isLeaf)
{
i=node->keynum-1;
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
while(i>=0&&key<node->key[i])
{
node->key[i+1]=node->key[i];
--i;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
node->key[i+1]=key;
++node->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//写入磁盘
disk_write(node);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//节点是内部节点
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
else
{
//查找插入的位置
i=node->keynum-1;
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
while(i>=0&&key<node->key[i])
{
--i;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
++i;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//从磁盘读取孩子节点
disk_read(&node->child[i]);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//如果该孩子节点已满,分裂调整值
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->child[i]->keynum==BTree_N)
{
BTree_split_child(node,i,node->child[i]);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(key>node->key[i])
{
++i;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_insert_nonfull(node->child[i],key);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_insert(BTree
*
tree,
int
key)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
BTNode*node;
BTNode*root=*tree;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//树为空
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(NULL==root)
{
root=(BTNode*)calloc(sizeof(BTNode),1);
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!root)
{
printf("Error!outofmemory!/n");
return;
}
root->isLeaf=true;
root->keynum=1;
root->key[0]=key;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
*tree=root;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//写入磁盘
disk_write(root);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//节点已满,需要进行分裂调整
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(root->keynum==BTree_N)
{
//产生新节点当作根
node=(BTNode*)calloc(sizeof(BTNode),1);
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!node)
{
printf("Error!outofmemory!/n");
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
*tree=node;
node->isLeaf=false;
node->keynum=0;
node->child[0]=root;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_split_child(node,0,root);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_insert_nonfull(node,key);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//节点未满,在当前节点中插入key
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
else
{
BTree_insert_nonfull(root,key);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
//
对tree中的节点node进行合并孩子节点处理
//
注意:孩子节点的keynum必须均已达到下限,即均等于BTree_T-1
//
将node中索引为index+1的孩子节点合并到索引为index的孩子节点中,
//
并将tree中索引为index的key下降到该节点中,调整相关的key和指针。
//
void
BTree_merge_child(BTree
*
tree,BTNode
*
node,
int
index)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
assert(tree&&node&&index>=0&&index<node->keynum);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
intkey=node->key[index];
BTNode*prevChild=node->child[index];
BTNode*nextChild=node->child[index+1];
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
assert(prevChild&&prevChild->keynum==BTree_T-1
&&nextChild&&nextChild->keynum==BTree_T-1);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
prevChild->key[prevChild->keynum]=key;
prevChild->child[prevChild->keynum+1]=nextChild->child[0];
++prevChild->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//合并
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<nextChild->keynum;++i)
{
prevChild->key[prevChild->keynum]=nextChild->key[i];
prevChild->child[prevChild->keynum+1]=nextChild->child[i+1];
++prevChild->keynum;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//在node中移除key以及指向后继孩子节点的指针
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=index;i<node->keynum-1;++i)
{
node->key[i]=node->key[i+1];
node->child[i+1]=node->child[i+2];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
node->key[node->keynum-1]=0;
node->child[node->keynum]=NULL;
--node->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//如果根节点没有key了,删之,并将根节点调整为前继孩子节点。
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->keynum==0)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(*tree==node)
{
*tree=prevChild;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
free(node);
node=NULL;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
free(nextChild);
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_remove(BTree
*
tree,
int
key)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
//B-数的保持条件之一:
//非根节点的内部节点的关键字数目不能少于BTree_T-1
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti,j,index;
BTNode*root=*tree;
BTNode*node=root;
BTNode*prevChild,*nextChild,*child;
intprevKey,nextKey;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!root)
{
printf("Failedtoremove%c,itisnotinthetree!/n",key);
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
index=0;
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
while(index<node->keynum&&key>node->key[index])
{
++index;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//
//indexofkey:i-1ii+1
//+---+---+---+---+---+
//
++A++![](https://i-blog.csdnimg.cn/blog_migrate/918e8df969f9f8c8d002f25cda86cade.gif)
//+---+---+---+---+---+
///|/
//indexofC:i-1ii+1
///|/
//+---+---++---++---+---+
//
++++++![](https://i-blog.csdnimg.cn/blog_migrate/918e8df969f9f8c8d002f25cda86cade.gif)
//+---+---++---++---+---+
//prevChildchildnextChild
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//Findthekey.
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(index<node->keynum&&node->key[index]==key)
{
//1,所在节点是叶子节点,直接删除
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->isLeaf)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=index;i<node->keynum;++i)
{
node->key[i]=node->key[i+1];
node->child[i+1]=node->child[i+2];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
--node->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node->keynum==0)
{
assert(node==*tree);
free(node);
*tree=NULL;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//2a,如果位于key前的子节点的key数目>=BTree_T,
//在其中找key的前驱,用前驱的key值赋予key,
//然后在前驱所在孩子节点中递归删除前驱。
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
elseif(node->child[index]->keynum>=BTree_T)
{
prevChild=node->child[index];
prevKey=prevChild->key[prevChild->keynum-1];
node->key[index]=prevKey;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_remove(&prevChild,prevKey);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//2b,如果位于key后的子节点的key数目>=BTree_T,
//在其中找key的后继,用后继的key值赋予key,
//然后在后继所在孩子节点中递归删除后继。
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
elseif(node->child[index+1]->keynum>=BTree_T)
{
nextChild=node->child[index+1];
nextKey=nextChild->key[0];
node->key[index]=nextKey;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_remove(&nextChild,nextKey);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//2c,前驱和后继都只包含BTree_T-1个节点,
//将key下降前驱孩子节点,并将后继孩子节点合并到前驱孩子节点,
//删除后继孩子节点,在node中移除key和指向后继孩子节点的指针,
//然后在前驱所在孩子节点中递归删除key。
elseif(node->child[index]->keynum==BTree_T-1
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
&&node->child[index+1]->keynum==BTree_T-1)
{
prevChild=node->child[index];
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_merge_child(tree,node,index);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//在前驱孩子节点中递归删除key
BTree_remove(&prevChild,key);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//3,key不在内节点node中,则应当在某个包含key的子节点中。
//key<node->key[index],所以key应当在孩子节点node->child[index]中
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
else
{
child=node->child[index];
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!child)
{
printf("Failedtoremove%c,itisnotinthetree!/n",key);
return;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(child->keynum==BTree_T-1)
{
prevChild=NULL;
nextChild=NULL;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(index-1>=0)
{
prevChild=node->child[index-1];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(index+1<=node->keynum)
{
nextChild=node->child[index+1];
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//3a,如果所在孩子节点相邻的兄弟节点中有节点至少包含BTree_t个关键字
//将node的一个关键字下降到child中,将相邻兄弟节点中一个节点上升到
//node中,然后在child孩子节点中递归删除key。
if((prevChild&&prevChild->keynum>=BTree_T)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
||(nextChild&&nextChild->keynum>=BTree_T))
{
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(nextChild&&nextChild->keynum>=BTree_T)
{
child->key[child->keynum]=node->key[index];
child->child[child->keynum+1]=nextChild->child[0];
++child->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
node->key[index]=nextChild->key[0];
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(j=0;j<nextChild->keynum-1;++j)
{
nextChild->key[j]=nextChild->key[j+1];
nextChild->child[j]=nextChild->child[j+1];
}
--nextChild->keynum;
}
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
else
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(j=child->keynum;j>0;--j)
{
child->key[j]=child->key[j-1];
child->child[j+1]=child->child[j];
}
child->child[1]=child->child[0];
child->child[0]=prevChild->child[prevChild->keynum];
child->key[0]=node->key[index-1];
++child->keynum;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
node->key[index-1]=prevChild->key[prevChild->keynum-1];
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
--prevChild->keynum;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//3b,如果所在孩子节点相邻的兄弟节点都只包含BTree_t-1个关键字,
//将child与其一相邻节点合并,并将node中的一个关键字下降到合并节点中,
//再在node中删除那个关键字和相关指针,若node的key为空,删之,并调整根。
//最后,在相关孩子节点中递归删除key。
elseif((!prevChild||(prevChild&&prevChild->keynum==BTree_T-1))
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
&&((!nextChild||nextChild&&nextChild->keynum==BTree_T-1)))
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(prevChild&&prevChild->keynum==BTree_T-1)
{
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_merge_child(tree,node,index-1);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
child=prevChild;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
elseif(nextChild&&nextChild->keynum==BTree_T-1)
{
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_merge_child(tree,node,index);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
BTree_remove(&child,key);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
BTNode
*
BTree_search(
const
BTreetree,
int
key,
int
*
pos)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(!tree)
{
returnNULL;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti=0;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
while(i<tree->keynum&&key>tree->key[i])
{
++i;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//Findthekey.
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(i<tree->keynum&&tree->key[i]==key)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(pos)
{
*pos=i;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
returntree;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//tree为叶子节点,找不到key,查找失败返回
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(tree->isLeaf)
{
returnNULL;
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//节点内查找失败,但tree->key[i-1]<key<tree->key[i],
//下一个查找的结点应为child[i]
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//从磁盘读取第i个孩子的数据
disk_read(&tree->child[i]);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
//递归地继续查找于树tree->child[i]
returnBTree_search(tree->child[i],key,pos);
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_create(BTree
*
tree,
const
int
*
data,
int
length)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
assert(tree);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
inti;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
#ifdefDEBUG_TREE
debug_print("/n开始创建B-树,关键字为:/n");
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<length;i++)
{
printf("%c",data[i]);
}
debug_print("/n");
#endif
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<length;i++)
{
#ifdefDEBUG_TREE
debug_print("/n插入关键字%c:/n",data[i]);
#endif
BTree_insert(tree,data[i]);
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
#ifdefDEBUG_TREE
BTree_print(*tree);
#endif
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
debug_print("/n");
}
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
void
BTree_destory(BTree
*
tree)
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
inti;
BTNode*node=*tree;
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
if(node)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
for(i=0;i<=node->keynum;i++)
{
BTree_destory(&node->child[i]);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
free(node);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
*tree=NULL;
}
测试代码:
//==================================================================
//测试B 树
//==================================================================
voidtest_BTree_search(BTreetree,intkey)
{
intpos=-1;
BTNode*node=BTree_search(tree,key,&pos);
if(node){
printf("在%s节点(包含%d个关键字)中找到关键字%c,其索引为%d/n",
node->isLeaf?"叶子":"非叶子",
node->keynum,key,pos);
}
else{
printf("在树中找不到关键字%c/n",key);
}
}
voidtest_BTree_remove(BTree*tree,intkey)
{
printf("/n移除关键字%c/n",key);
BTree_remove(tree,key);
BTree_print(*tree);
printf("/n");
}
voidtest_btree()
{
constintlength=10;
intarray[length]={
'G','M','P','X','A','C','D','E','J','K',
//'N','O','R','S','T','U','V','Y','Z','F'
};
BTreetree=NULL;
BTNode*node=NULL;
intpos=-1;
intkey1='R';//inthetree.
intkey2='B';//notinthetree.
//创建
BTree_create(&tree,array,length);
printf("/n===创建B-树===/n");
BTree_print(tree);
printf("/n");
//查找
test_BTree_search(tree,key1);
printf("/n");
test_BTree_search(tree,key2);
//插入关键字
printf("/n插入关键字%c/n",key2);
BTree_insert(&tree,key2);
BTree_print(tree);
printf("/n");
test_BTree_search(tree,key2);
//移除关键字
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='M';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='E';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='G';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='A';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='D';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='K';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='P';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='J';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='C';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
key2='X';
test_BTree_remove(&tree,key2);
test_BTree_search(tree,key2);
//销毁
BTree_destory(&tree);
}
测试结果:
===创建B 树===
第1层,1node:E
第2层,1node:C
第3层,1node:A
第3层,1node:D
第2层,1node:M
第3层,3node:GJK
第3层,2node:PX
从磁盘读取节点
从磁盘读取节点
在树中找不到关键字R
从磁盘读取节点
从磁盘读取节点
在树中找不到关键字B
插入关键字B
从磁盘读取节点
从磁盘读取节点
向磁盘写入节点
第1层,1node:E
第2层,1node:C
第3层,2node:AB
第3层,1node:D
第2层,1node:M
第3层,3node:GJK
第3层,2node:PX
从磁盘读取节点
从磁盘读取节点
在叶子节点(包含2个关键字)中找到关键字B,其索引为1
.......
参考资料:
1,《算法导论》