from http://www.sqlite.com.cn/MySqlite/6/373.Html
这个结构一般用于数据库的索引,综合效率非常高,像 Berkerly DB , sqlite , mysql 数据库都使用了这个算法处理索引。
如果想自己做个小型数据库,可能参考一下这个算法的实现,可能会对你有所帮助。
其中的注释很详细,不用再多说了。
/*
btrees.h
*/
/*
* 平衡多路树的一种重要方案。
* 在 1970 年由 R. Bayer 和 E. McCreight 发明。
*/
#define M 1
/* B 树的阶,即非根节点中键的最小数目。
* 有些人把阶定义为非根节点中子树的最大数目。
*/
typedef int typekey;
typedef struct btnode { /* B-Tree 节点 */
int d; /* 节点中键的数目 */
typekey k[ 2 * M]; /* 键 */
char * v[ 2 * M]; /* 值 */
struct btnode * p[ 2 * M + 1 ]; /* 指向子树的指针 */
} node, * btree;
/*
* 每个键的左子树中的所有的键都小于这个键,
* 每个键的右子树中的所有的键都大于等于这个键。
* 叶子节点中的每个键都没有子树。
*/
/* 当 M 等于 1 时也称为 2-3 树
* +----+----+
* | k0 | k1 |
* +-+----+----+---
* | p0 | p1 | p2 |
* +----+----+----+
*/
extern int btree_disp; /* 查找时找到的键在节点中的位置 */
extern char * InsValue; /* 与要插的键相对应的值 */
extern btree search(typekey, btree);
extern btree insert(typekey,btree);
extern btree delete(typekey,btree);
extern int height(btree);
extern int count(btree);
extern double payload(btree);
extern btree deltree(btree);
/* end of btrees.h */
/* ***************************************************** */
/*
* 平衡多路树的一种重要方案。
* 在 1970 年由 R. Bayer 和 E. McCreight 发明。
*/
#define M 1
/* B 树的阶,即非根节点中键的最小数目。
* 有些人把阶定义为非根节点中子树的最大数目。
*/
typedef int typekey;
typedef struct btnode { /* B-Tree 节点 */
int d; /* 节点中键的数目 */
typekey k[ 2 * M]; /* 键 */
char * v[ 2 * M]; /* 值 */
struct btnode * p[ 2 * M + 1 ]; /* 指向子树的指针 */
} node, * btree;
/*
* 每个键的左子树中的所有的键都小于这个键,
* 每个键的右子树中的所有的键都大于等于这个键。
* 叶子节点中的每个键都没有子树。
*/
/* 当 M 等于 1 时也称为 2-3 树
* +----+----+
* | k0 | k1 |
* +-+----+----+---
* | p0 | p1 | p2 |
* +----+----+----+
*/
extern int btree_disp; /* 查找时找到的键在节点中的位置 */
extern char * InsValue; /* 与要插的键相对应的值 */
extern btree search(typekey, btree);
extern btree insert(typekey,btree);
extern btree delete(typekey,btree);
extern int height(btree);
extern int count(btree);
extern double payload(btree);
extern btree deltree(btree);
/* end of btrees.h */
/* ***************************************************** */
/*
*****************************************************
*/
/* btrees.c */
#include
#include
#include " btrees.h "
btree search(typekey, btree);
btree insert(typekey,btree);
btree delete(typekey,btree);
int height(btree);
int count(btree);
double payload(btree);
btree deltree(btree);
static void InternalInsert(typekey, btree);
static void InsInNode(btree, int );
static void SplitNode(btree, int );
static btree NewRoot(btree);
static void InternalDelete(typekey, btree);
static void JoinNode(btree, int );
static void MoveLeftNode(btree t, int );
static void MoveRightNode(btree t, int );
static void DelFromNode(btree t, int );
static btree FreeRoot(btree);
static btree delall(btree);
static void Error( int ,typekey);
int btree_disp; /* 查找时找到的键在节点中的位置 */
char * InsValue = NULL; /* 与要插的键相对应的值 */
static int flag; /* 节点增减标志 */
static int btree_level = 0 ; /* 多路树的高度 */
static int btree_count = 0 ; /* 多路树的键总数 */
static int node_sum = 0 ; /* 多路树的节点总数 */
static int level; /* 当前访问的节点所处的高度 */
static btree NewTree; /* 在节点分割的时候指向新建的节点 */
static typekey InsKey; /* 要插入的键 */
btree search(typekey key, btree t)
{
int i,j,m;
level = btree_level - 1 ;
while (level >= 0 ){
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k){
btree_disp = i;
return t;
}
if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
t = t -> p;
level -- ;
}
return NULL;
}
btree insert(typekey key, btree t)
{
level = btree_level;
InternalInsert(key, t);
if (flag == 1 ) /* 根节点满之后,它被分割成两个半满节点 */
t = NewRoot(t); /* 树的高度增加 */
return t;
}
void InternalInsert(typekey key, btree t)
{
int i,j,m;
level -- ;
if (level < 0 ){ /* 到达了树的底部: 指出要做的插入 */
NewTree = NULL; /* 这个键没有对应的子树 */
InsKey = key; /* 导致底层的叶子节点增加键值+空子树对 */
btree_count ++ ;
flag = 1 ; /* 指示上层节点把返回的键插入其中 */
return ;
}
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k) {
Error( 1 ,key); /* 键已经在树中 */
flag = 0 ;
return ;
}
if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
InternalInsert(key, t -> p);
if (flag == 0 )
return ;
/* 有新键要插入到当前节点中 */
if (t -> d < 2 * M) { /* 当前节点未满 */
InsInNode(t, i); /* 把键值+子树对插入当前节点中 */
flag = 0 ; /* 指示上层节点没有需要插入的键值+子树,插入过程结束 */
}
else /* 当前节点已满,则分割这个页面并把键值+子树对插入当前节点中 */
SplitNode(t, i); /* 继续指示上层节点把返回的键值+子树插入其中 */
}
/*
* 把一个键和对应的右子树插入一个节点中
*/
void InsInNode(btree t, int d)
{
int i;
/* 把所有大于要插入的键值的键和对应的右子树右移 */
for (i = t -> d; i > d; i -- ){
t -> k = t -> k[i - 1 ];
t -> v = t -> v[i - 1 ];
t -> p[i + 1 ] = t -> p;
}
/* 插入键和右子树 */
t -> k = InsKey;
t -> p[i + 1 ] = NewTree;
t -> v = InsValue;
t -> d ++ ;
}
/*
* 前件是要插入一个键和对应的右子树,并且本节点已经满
* 导致分割这个节点,插入键和对应的右子树,
* 并向上层返回一个要插入键和对应的右子树
*/
void SplitNode(btree t, int d)
{
int i,j;
btree temp;
typekey temp_k;
char * temp_v;
/* 建立新节点 */
temp = (btree)malloc( sizeof (node));
/*
* +---+--------+-----+-----+--------+-----+
* | 0 | | M | M+1 | |2*M-1|
* +---+--------+-----+-----+--------+-----+
* |<- M+1 ->|<- M-1 ->|
*/
if (d > M) { /* 要插入当前节点的右半部分 */
/* 把从 2*M-1 到 M+1 的 M-1 个键值+子树对转移到新节点中,
* 并且为要插入的键值+子树空出位置 */
for (i = 2 * M - 1 ,j = M - 1 ; i >= d; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
for (i = d - 1 ,j = d - M - 2 ; j >= 0 ; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
/* 把节点的最右子树转移成新节点的最左子树 */
temp -> p[ 0 ] = t -> p[M + 1 ];
/* 在新节点中插入键和右子树 */
temp -> k[d - M - 1 ] = InsKey;
temp -> p[d - M] = NewTree;
temp -> v[d - M - 1 ] = InsValue;
/* 设置要插入上层节点的键和值 */
InsKey = t -> k[M];
InsValue = t -> v[M];
}
else { /* d <= M */
/* 把从 2*M-1 到 M 的 M 个键值+子树对转移到新节点中 */
for (i = 2 * M - 1 ,j = M - 1 ; j >= 0 ; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
if (d == M) /* 要插入当前节点的正中间 */
/* 把要插入的子树作为新节点的最左子树 */
temp -> p[ 0 ] = NewTree;
/* 直接把要插入的键和值返回给上层节点 */
else { /* (d /* 把节点当前的最右子树转移成新节点的最左子树 */
temp -> p[ 0 ] = t -> p[M];
/* 保存要插入上层节点的键和值 */
temp_k = t -> k[M - 1 ];
temp_v = t -> v[M - 1 ];
/* 把所有大于要插入的键值的键和对应的右子树右移 */
for (i = M - 1 ; i > d; i -- ) {
t -> k = t -> k[i - 1 ];
t -> v = t -> v[i - 1 ];
t -> p[i + 1 ] = t -> p;
}
/* 在节点中插入键和右子树 */
t -> k[d] = InsKey;
t -> p[d + 1 ] = NewTree;
t -> v[d] = InsValue;
/* 设置要插入上层节点的键和值 */
InsKey = temp_k;
InsValue = temp_v;
}
}
t -> d = M;
temp -> d = M;
NewTree = temp;
node_sum ++ ;
}
btree delete(typekey key, btree t)
{
level = btree_level;
InternalDelete(key, t);
if (t -> d == 0 )
/* 根节点的子节点合并导致根节点键的数目随之减少,
* 当根节点中没有键的时候,只有它的最左子树可能非空 */
t = FreeRoot(t);
return t;
}
void InternalDelete(typekey key, btree t)
{
int i,j,m;
btree l,r;
int lvl;
level -- ;
if (level < 0 ) {
Error( 0 ,key); /* 在整个树中未找到要删除的键 */
flag = 0 ;
return ;
}
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k) { /* 找到要删除的键 */
if (t -> v != NULL)
free(t -> v); /* 释放这个节点包含的值 */
if (level == 0 ) { /* 有子树为空则这个键位于叶子节点 */
DelFromNode(t,i);
btree_count -- ;
flag = 1 ;
/* 指示上层节点本子树的键数量减少 */
return ;
} else { /* 这个键位于非叶节点 */
lvl = level - 1 ;
/* 找到前驱节点 */
r = t -> p;
while (lvl > 0 ) {
r = r -> p[r -> d];
lvl -- ;
}
t -> k = r -> k[r -> d - 1 ];
t -> v = r -> v[r -> d - 1 ];
r -> v[r -> d - 1 ] = NULL;
key = r -> k[r -> d - 1 ];
}
}
else if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
InternalDelete(key,t -> p);
/* 调整平衡 */
if (flag == 0 )
return ;
if (t -> p -> d < M) {
if (i == t -> d) /* 在最右子树中发生了删除 */
i -- ; /* 调整最右键的左右子树平衡 */
l = t -> p;
r = t -> p[i + 1 ];
if (r -> d > M)
MoveLeftNode(t,i);
else if (l -> d > M)
MoveRightNode(t,i);
else {
JoinNode(t,i);
/* 继续指示上层节点本子树的键数量减少 */
return ;
}
flag = 0 ;
/* 指示上层节点本子树的键数量没有减少,删除过程结束 */
}
}
/*
* 合并一个节点的某个键对应的两个子树
*/
void JoinNode(btree t, int d)
{
btree l,r;
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
/* 把这个键下移到它的左子树 */
l -> k[l -> d] = t -> k[d];
l -> v[l -> d] = t -> v[d];
/* 把右子树中的所有键值和子树转移到左子树 */
for (j = r -> d - 1 ,i = l -> d + r -> d; j >= 0 ; j -- ,i -- ) {
l -> k = r -> k[j];
l -> v = r -> v[j];
l -> p = r -> p[j];
}
l -> p[l -> d + r -> d + 1 ] = r -> p[r -> d];
l -> d += r -> d + 1 ;
/* 释放右子树的节点 */
free(r);
/* 把这个键右边的键和对应的右子树左移 */
for (i = d; i < t -> d - 1 ; i ++ ) {
t -> k = t -> k[i + 1 ];
t -> v = t -> v[i + 1 ];
t -> p[i + 1 ] = t -> p[i + 2 ];
}
t -> d -- ;
node_sum -- ;
}
/*
* 从一个键的右子树向左子树转移一些键,使两个子树平衡
*/
void MoveLeftNode(btree t, int d)
{
btree l,r;
int m; /* 应转移的键的数目 */
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
m = (r -> d - l -> d) / 2 ;
/* 把这个键下移到它的左子树 */
l -> k[l -> d] = t -> k[d];
l -> v[l -> d] = t -> v[d];
/* 把右子树的最左子树转移成左子树的最右子树
* 从右子树向左子树移动 m-1 个键+子树对 */
for (j = m - 2 ,i = l -> d + m - 1 ; j >= 0 ; j -- ,i -- ) {
l -> k = r -> k[j];
l -> v = r -> v[j];
l -> p = r -> p[j];
}
l -> p[l -> d + m] = r -> p[m - 1 ];
/* 把右子树的最左键提升到这个键的位置上 */
t -> k[d] = r -> k[m - 1 ];
t -> v[d] = r -> v[m - 1 ];
/* 把右子树中的所有键值和子树左移 m 个位置 */
r -> p[ 0 ] = r -> p[m];
for (i = 0 ; id - m; i ++ ) {
r -> k = r -> k[i + m];
r -> v = r -> v[i + m];
r -> p = r -> p[i + m];
}
r -> p[r -> d - m] = r -> p[r -> d];
l -> d += m;
r -> d -= m;
}
/*
* 从一个键的左子树向右子树转移一些键,使两个子树平衡
*/
void MoveRightNode(btree t, int d)
{
btree l,r;
int m; /* 应转移的键的数目 */
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
m = (l -> d - r -> d) / 2 ;
/* 把右子树中的所有键值和子树右移 m 个位置 */
r -> p[r -> d + m] = r -> p[r -> d];
for (i = r -> d - 1 ; i >= 0 ; i -- ) {
r -> k[i + m] = r -> k;
r -> v[i + m] = r -> v;
r -> p[i + m] = r -> p;
}
/* 把这个键下移到它的右子树 */
r -> k[m - 1 ] = t -> k[d];
r -> v[m - 1 ] = t -> v[d];
/* 把左子树的最右子树转移成右子树的最左子树 */
r -> p[m - 1 ] = l -> p[l -> d];
/* 从左子树向右子树移动 m-1 个键+子树对 */
for (i = l -> d - 1 ,j = m - 2 ; j >= 0 ; j -- ,i -- ) {
r -> k[j] = l -> k;
r -> v[j] = l -> v;
r -> p[j] = l -> p;
}
/* 把左子树的最右键提升到这个键的位置上 */
t -> k[d] = l -> k;
t -> v[d] = l -> v;
l -> d -= m;
r -> d += m;
}
/*
* 把一个键和对应的右子树从一个节点中删除
*/
void DelFromNode(btree t, int d)
{
int i;
/* 把所有大于要删除的键值的键左移 */
for (i = d; i < t -> d - 1 ; i ++ ) {
t -> k = t -> k[i + 1 ];
t -> v = t -> v[i + 1 ];
}
t -> d -- ;
}
/*
* 建立有两个子树和一个键的根节点
*/
btree NewRoot(btree t)
{
btree temp;
temp = (btree)malloc( sizeof (node));
temp -> d = 1 ;
temp -> p[ 0 ] = t;
temp -> p[ 1 ] = NewTree;
temp -> k[ 0 ] = InsKey;
temp -> v[ 0 ] = InsValue;
btree_level ++ ;
node_sum ++ ;
return (temp);
}
/*
* 释放根节点,并返回它的最左子树
*/
btree FreeRoot(btree t)
{
btree temp;
temp = t -> p[ 0 ];
free(t);
btree_level -- ;
node_sum -- ;
return temp;
}
void Error( int f,typekey key)
{
if (f)
printf( " Btrees error: Insert %d! " ,key);
else
printf( " Btrees error: delete %d! " ,key);
}
int height(btree t)
{
return btree_level;
}
int count(btree t)
{
return btree_count;
}
double payload(btree t)
{
if (node_sum == 0 )
return 1 ;
return ( double )btree_count / (node_sum * ( 2 * M));
}
btree deltree (btree t)
{
level = btree_level;
btree_level = 0 ;
return delall(t);
}
btree delall(btree t)
{
int i;
level -- ;
if (level >= 0 ) {
for (i = 0 ; i < t -> d; i ++ )
if (t -> v != NULL)
free(t -> v);
if (level > 0 )
for (i = 0 ; i <= t -> d ; i ++ )
t -> p = delall(t -> p);
free(t);
}
return NULL;
}
/* end of btrees.c */
/* btrees.c */
#include
#include
#include " btrees.h "
btree search(typekey, btree);
btree insert(typekey,btree);
btree delete(typekey,btree);
int height(btree);
int count(btree);
double payload(btree);
btree deltree(btree);
static void InternalInsert(typekey, btree);
static void InsInNode(btree, int );
static void SplitNode(btree, int );
static btree NewRoot(btree);
static void InternalDelete(typekey, btree);
static void JoinNode(btree, int );
static void MoveLeftNode(btree t, int );
static void MoveRightNode(btree t, int );
static void DelFromNode(btree t, int );
static btree FreeRoot(btree);
static btree delall(btree);
static void Error( int ,typekey);
int btree_disp; /* 查找时找到的键在节点中的位置 */
char * InsValue = NULL; /* 与要插的键相对应的值 */
static int flag; /* 节点增减标志 */
static int btree_level = 0 ; /* 多路树的高度 */
static int btree_count = 0 ; /* 多路树的键总数 */
static int node_sum = 0 ; /* 多路树的节点总数 */
static int level; /* 当前访问的节点所处的高度 */
static btree NewTree; /* 在节点分割的时候指向新建的节点 */
static typekey InsKey; /* 要插入的键 */
btree search(typekey key, btree t)
{
int i,j,m;
level = btree_level - 1 ;
while (level >= 0 ){
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k){
btree_disp = i;
return t;
}
if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
t = t -> p;
level -- ;
}
return NULL;
}
btree insert(typekey key, btree t)
{
level = btree_level;
InternalInsert(key, t);
if (flag == 1 ) /* 根节点满之后,它被分割成两个半满节点 */
t = NewRoot(t); /* 树的高度增加 */
return t;
}
void InternalInsert(typekey key, btree t)
{
int i,j,m;
level -- ;
if (level < 0 ){ /* 到达了树的底部: 指出要做的插入 */
NewTree = NULL; /* 这个键没有对应的子树 */
InsKey = key; /* 导致底层的叶子节点增加键值+空子树对 */
btree_count ++ ;
flag = 1 ; /* 指示上层节点把返回的键插入其中 */
return ;
}
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k) {
Error( 1 ,key); /* 键已经在树中 */
flag = 0 ;
return ;
}
if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
InternalInsert(key, t -> p);
if (flag == 0 )
return ;
/* 有新键要插入到当前节点中 */
if (t -> d < 2 * M) { /* 当前节点未满 */
InsInNode(t, i); /* 把键值+子树对插入当前节点中 */
flag = 0 ; /* 指示上层节点没有需要插入的键值+子树,插入过程结束 */
}
else /* 当前节点已满,则分割这个页面并把键值+子树对插入当前节点中 */
SplitNode(t, i); /* 继续指示上层节点把返回的键值+子树插入其中 */
}
/*
* 把一个键和对应的右子树插入一个节点中
*/
void InsInNode(btree t, int d)
{
int i;
/* 把所有大于要插入的键值的键和对应的右子树右移 */
for (i = t -> d; i > d; i -- ){
t -> k = t -> k[i - 1 ];
t -> v = t -> v[i - 1 ];
t -> p[i + 1 ] = t -> p;
}
/* 插入键和右子树 */
t -> k = InsKey;
t -> p[i + 1 ] = NewTree;
t -> v = InsValue;
t -> d ++ ;
}
/*
* 前件是要插入一个键和对应的右子树,并且本节点已经满
* 导致分割这个节点,插入键和对应的右子树,
* 并向上层返回一个要插入键和对应的右子树
*/
void SplitNode(btree t, int d)
{
int i,j;
btree temp;
typekey temp_k;
char * temp_v;
/* 建立新节点 */
temp = (btree)malloc( sizeof (node));
/*
* +---+--------+-----+-----+--------+-----+
* | 0 | | M | M+1 | |2*M-1|
* +---+--------+-----+-----+--------+-----+
* |<- M+1 ->|<- M-1 ->|
*/
if (d > M) { /* 要插入当前节点的右半部分 */
/* 把从 2*M-1 到 M+1 的 M-1 个键值+子树对转移到新节点中,
* 并且为要插入的键值+子树空出位置 */
for (i = 2 * M - 1 ,j = M - 1 ; i >= d; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
for (i = d - 1 ,j = d - M - 2 ; j >= 0 ; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
/* 把节点的最右子树转移成新节点的最左子树 */
temp -> p[ 0 ] = t -> p[M + 1 ];
/* 在新节点中插入键和右子树 */
temp -> k[d - M - 1 ] = InsKey;
temp -> p[d - M] = NewTree;
temp -> v[d - M - 1 ] = InsValue;
/* 设置要插入上层节点的键和值 */
InsKey = t -> k[M];
InsValue = t -> v[M];
}
else { /* d <= M */
/* 把从 2*M-1 到 M 的 M 个键值+子树对转移到新节点中 */
for (i = 2 * M - 1 ,j = M - 1 ; j >= 0 ; i -- ,j -- ) {
temp -> k[j] = t -> k;
temp -> v[j] = t -> v;
temp -> p[j + 1 ] = t -> p[i + 1 ];
}
if (d == M) /* 要插入当前节点的正中间 */
/* 把要插入的子树作为新节点的最左子树 */
temp -> p[ 0 ] = NewTree;
/* 直接把要插入的键和值返回给上层节点 */
else { /* (d /* 把节点当前的最右子树转移成新节点的最左子树 */
temp -> p[ 0 ] = t -> p[M];
/* 保存要插入上层节点的键和值 */
temp_k = t -> k[M - 1 ];
temp_v = t -> v[M - 1 ];
/* 把所有大于要插入的键值的键和对应的右子树右移 */
for (i = M - 1 ; i > d; i -- ) {
t -> k = t -> k[i - 1 ];
t -> v = t -> v[i - 1 ];
t -> p[i + 1 ] = t -> p;
}
/* 在节点中插入键和右子树 */
t -> k[d] = InsKey;
t -> p[d + 1 ] = NewTree;
t -> v[d] = InsValue;
/* 设置要插入上层节点的键和值 */
InsKey = temp_k;
InsValue = temp_v;
}
}
t -> d = M;
temp -> d = M;
NewTree = temp;
node_sum ++ ;
}
btree delete(typekey key, btree t)
{
level = btree_level;
InternalDelete(key, t);
if (t -> d == 0 )
/* 根节点的子节点合并导致根节点键的数目随之减少,
* 当根节点中没有键的时候,只有它的最左子树可能非空 */
t = FreeRoot(t);
return t;
}
void InternalDelete(typekey key, btree t)
{
int i,j,m;
btree l,r;
int lvl;
level -- ;
if (level < 0 ) {
Error( 0 ,key); /* 在整个树中未找到要删除的键 */
flag = 0 ;
return ;
}
for (i = 0 , j = t -> d - 1 ; i t -> k[m]) ? (i = m + 1 ):(j = m));
if (key == t -> k) { /* 找到要删除的键 */
if (t -> v != NULL)
free(t -> v); /* 释放这个节点包含的值 */
if (level == 0 ) { /* 有子树为空则这个键位于叶子节点 */
DelFromNode(t,i);
btree_count -- ;
flag = 1 ;
/* 指示上层节点本子树的键数量减少 */
return ;
} else { /* 这个键位于非叶节点 */
lvl = level - 1 ;
/* 找到前驱节点 */
r = t -> p;
while (lvl > 0 ) {
r = r -> p[r -> d];
lvl -- ;
}
t -> k = r -> k[r -> d - 1 ];
t -> v = r -> v[r -> d - 1 ];
r -> v[r -> d - 1 ] = NULL;
key = r -> k[r -> d - 1 ];
}
}
else if (key > t -> k) /* i == t->d-1 时有可能出现 */
i ++ ;
InternalDelete(key,t -> p);
/* 调整平衡 */
if (flag == 0 )
return ;
if (t -> p -> d < M) {
if (i == t -> d) /* 在最右子树中发生了删除 */
i -- ; /* 调整最右键的左右子树平衡 */
l = t -> p;
r = t -> p[i + 1 ];
if (r -> d > M)
MoveLeftNode(t,i);
else if (l -> d > M)
MoveRightNode(t,i);
else {
JoinNode(t,i);
/* 继续指示上层节点本子树的键数量减少 */
return ;
}
flag = 0 ;
/* 指示上层节点本子树的键数量没有减少,删除过程结束 */
}
}
/*
* 合并一个节点的某个键对应的两个子树
*/
void JoinNode(btree t, int d)
{
btree l,r;
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
/* 把这个键下移到它的左子树 */
l -> k[l -> d] = t -> k[d];
l -> v[l -> d] = t -> v[d];
/* 把右子树中的所有键值和子树转移到左子树 */
for (j = r -> d - 1 ,i = l -> d + r -> d; j >= 0 ; j -- ,i -- ) {
l -> k = r -> k[j];
l -> v = r -> v[j];
l -> p = r -> p[j];
}
l -> p[l -> d + r -> d + 1 ] = r -> p[r -> d];
l -> d += r -> d + 1 ;
/* 释放右子树的节点 */
free(r);
/* 把这个键右边的键和对应的右子树左移 */
for (i = d; i < t -> d - 1 ; i ++ ) {
t -> k = t -> k[i + 1 ];
t -> v = t -> v[i + 1 ];
t -> p[i + 1 ] = t -> p[i + 2 ];
}
t -> d -- ;
node_sum -- ;
}
/*
* 从一个键的右子树向左子树转移一些键,使两个子树平衡
*/
void MoveLeftNode(btree t, int d)
{
btree l,r;
int m; /* 应转移的键的数目 */
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
m = (r -> d - l -> d) / 2 ;
/* 把这个键下移到它的左子树 */
l -> k[l -> d] = t -> k[d];
l -> v[l -> d] = t -> v[d];
/* 把右子树的最左子树转移成左子树的最右子树
* 从右子树向左子树移动 m-1 个键+子树对 */
for (j = m - 2 ,i = l -> d + m - 1 ; j >= 0 ; j -- ,i -- ) {
l -> k = r -> k[j];
l -> v = r -> v[j];
l -> p = r -> p[j];
}
l -> p[l -> d + m] = r -> p[m - 1 ];
/* 把右子树的最左键提升到这个键的位置上 */
t -> k[d] = r -> k[m - 1 ];
t -> v[d] = r -> v[m - 1 ];
/* 把右子树中的所有键值和子树左移 m 个位置 */
r -> p[ 0 ] = r -> p[m];
for (i = 0 ; id - m; i ++ ) {
r -> k = r -> k[i + m];
r -> v = r -> v[i + m];
r -> p = r -> p[i + m];
}
r -> p[r -> d - m] = r -> p[r -> d];
l -> d += m;
r -> d -= m;
}
/*
* 从一个键的左子树向右子树转移一些键,使两个子树平衡
*/
void MoveRightNode(btree t, int d)
{
btree l,r;
int m; /* 应转移的键的数目 */
int i,j;
l = t -> p[d];
r = t -> p[d + 1 ];
m = (l -> d - r -> d) / 2 ;
/* 把右子树中的所有键值和子树右移 m 个位置 */
r -> p[r -> d + m] = r -> p[r -> d];
for (i = r -> d - 1 ; i >= 0 ; i -- ) {
r -> k[i + m] = r -> k;
r -> v[i + m] = r -> v;
r -> p[i + m] = r -> p;
}
/* 把这个键下移到它的右子树 */
r -> k[m - 1 ] = t -> k[d];
r -> v[m - 1 ] = t -> v[d];
/* 把左子树的最右子树转移成右子树的最左子树 */
r -> p[m - 1 ] = l -> p[l -> d];
/* 从左子树向右子树移动 m-1 个键+子树对 */
for (i = l -> d - 1 ,j = m - 2 ; j >= 0 ; j -- ,i -- ) {
r -> k[j] = l -> k;
r -> v[j] = l -> v;
r -> p[j] = l -> p;
}
/* 把左子树的最右键提升到这个键的位置上 */
t -> k[d] = l -> k;
t -> v[d] = l -> v;
l -> d -= m;
r -> d += m;
}
/*
* 把一个键和对应的右子树从一个节点中删除
*/
void DelFromNode(btree t, int d)
{
int i;
/* 把所有大于要删除的键值的键左移 */
for (i = d; i < t -> d - 1 ; i ++ ) {
t -> k = t -> k[i + 1 ];
t -> v = t -> v[i + 1 ];
}
t -> d -- ;
}
/*
* 建立有两个子树和一个键的根节点
*/
btree NewRoot(btree t)
{
btree temp;
temp = (btree)malloc( sizeof (node));
temp -> d = 1 ;
temp -> p[ 0 ] = t;
temp -> p[ 1 ] = NewTree;
temp -> k[ 0 ] = InsKey;
temp -> v[ 0 ] = InsValue;
btree_level ++ ;
node_sum ++ ;
return (temp);
}
/*
* 释放根节点,并返回它的最左子树
*/
btree FreeRoot(btree t)
{
btree temp;
temp = t -> p[ 0 ];
free(t);
btree_level -- ;
node_sum -- ;
return temp;
}
void Error( int f,typekey key)
{
if (f)
printf( " Btrees error: Insert %d! " ,key);
else
printf( " Btrees error: delete %d! " ,key);
}
int height(btree t)
{
return btree_level;
}
int count(btree t)
{
return btree_count;
}
double payload(btree t)
{
if (node_sum == 0 )
return 1 ;
return ( double )btree_count / (node_sum * ( 2 * M));
}
btree deltree (btree t)
{
level = btree_level;
btree_level = 0 ;
return delall(t);
}
btree delall(btree t)
{
int i;
level -- ;
if (level >= 0 ) {
for (i = 0 ; i < t -> d; i ++ )
if (t -> v != NULL)
free(t -> v);
if (level > 0 )
for (i = 0 ; i <= t -> d ; i ++ )
t -> p = delall(t -> p);
free(t);
}
return NULL;
}
/* end of btrees.c */