B树算法与实现C语言描述.docx
- 文档编号:29629739
- 上传时间:2023-07-25
- 格式:DOCX
- 页数:14
- 大小:19.20KB
B树算法与实现C语言描述.docx
《B树算法与实现C语言描述.docx》由会员分享,可在线阅读,更多相关《B树算法与实现C语言描述.docx(14页珍藏版)》请在冰豆网上搜索。
B树算法与实现C语言描述
这个结构一般用于数据库的索引,综合效率较高。
另外还有一种与此类似的树结构叫B+树,像BerkerlyDB,sqlite,mysql数据库都使用了B+树算法处理索引。
这两种处理索引的数据结构的不同之处:
1。
B树中同一键值不会出现多次,并且它有可能出现在叶结点,也有可能出现在非叶结点中。
而B+树的键一定会出现在叶结点中,并且有可能在非叶结点中也有可能重复出现,以维持B+树的平衡。
2。
因为B树键位置不定,且在整个树结构中只出现一次,虽然可以节省存储空间,但使得在插入、删除操作复杂度明显增加。
B+树相比来说是一种较好的折中。
3。
B树的查询效率与键在树中的位置有关,最大时间复杂度与B+树相同(在叶结点的时候),最小时间复杂度为1(在根结点的时候)。
而B+树的时候复杂度对某建成的树是固定的。
如果想自己做个小型数据库,可以参考一下下面给出的B树算法的实现,可能会对你有所帮助。
其中的注册很详细,不用再多说了。
/*btrees.h*/
/*
*平衡多路树的一种重要方案。
*在1970年由R.Bayer和E.McCreight发明。
*/
#defineM1
/*B树的阶,即非根节点中键的最小数目。
*有些人把阶定义为非根节点中子树的最大数目。
*/
typedefinttypekey;
typedefstructbtnode{ /*B-Tree节点*/
intd; /*节点中键的数目*/
typekeyk[2*M]; /*键*/
char*v[2*M]; /*值*/
structbtnode*p[2*M+1]; /*指向子树的指针*/
}node,*btree;
/*
*每个键的左子树中的所有的键都小于这个键,
*每个键的右子树中的所有的键都大于等于这个键。
*叶子节点中的每个键都没有子树。
*/
/*当M等于1时也称为2-3树
* +----+----+
* |k0|k1|
* +-+----+----+---
* |p0|p1|p2|
* +----+----+----+
*/
externintbtree_disp;/*查找时找到的键在节点中的位置*/
externchar*InsValue;/*与要插的键相对应的值*/
externbtreesearch(typekey,btree);
externbtreeinsert(typekey,btree);
externbtreedelete(typekey,btree);
externintheight(btree);
externintcount(btree);
externdoublepayload(btree);
externbtreedeltree(btree);
/*endofbtrees.h*/
/*******************************************************/
/*btrees.c*/
#include
#include
#include"btrees.h"
btreesearch(typekey,btree);
btreeinsert(typekey,btree);
btreedelete(typekey,btree);
intheight(btree);
intcount(btree);
doublepayload(btree);
btreedeltree(btree);
staticvoidInternalInsert(typekey,btree);
staticvoidInsInNode(btree,int);
staticvoidSplitNode(btree,int);
staticbtreeNewRoot(btree);
staticvoidInternalDelete(typekey,btree);
staticvoidJoinNode(btree,int);
staticvoidMoveLeftNode(btreet,int);
staticvoidMoveRightNode(btreet,int);
staticvoidDelFromNode(btreet,int);
staticbtreeFreeRoot(btree);
staticbtreedelall(btree);
staticvoidError(int,typekey);
intbtree_disp;/*查找时找到的键在节点中的位置*/
char*InsValue=NULL;/*与要插的键相对应的值*/
staticintflag;/*节点增减标志*/
staticintbtree_level=0;/*多路树的高度*/
staticintbtree_count=0;/*多路树的键总数*/
staticintnode_sum=0; /*多路树的节点总数*/
staticintlevel;/*当前访问的节点所处的高度*/
staticbtreeNewTree;/*在节点分割的时候指向新建的节点*/
statictypekeyInsKey;/*要插入的键*/
btreesearch(typekeykey,btreet)
{
inti,j,m;
level=btree_level-1;
while(level>=0){
for(i=0,j=t->d-1;i
(i=m+1):
(j=m));
if(key==t->k[i]){
btree_disp=i;
returnt;
}
if(key>t->k[i])/*i==t->d-1时有可能出现*/
i++;
t=t->p[i];
level--;
}
returnNULL;
}
btreeinsert(typekeykey,btreet)
{
level=btree_level;
InternalInsert(key,t);
if(flag==1) /*根节点满之后,它被分割成两个半满节点*/
t=NewRoot(t); /*树的高度增加*/
returnt;
}
voidInternalInsert(typekeykey,btreet)
{
inti,j,m;
level--;
if(level<0){/*到达了树的底部:
指出要做的插入*/
NewTree=NULL;/*这个键没有对应的子树*/
InsKey=key;/*导致底层的叶子节点增加键值+空子树对*/
btree_count++;
flag=1;/*指示上层节点把返回的键插入其中*/
return;
}
for(i=0,j=t->d-1;i
(i=m+1):
(j=m));
if(key==t->k[i]){
Error(1,key);/*键已经在树中*/
flag=0;
return;
}
if(key>t->k[i])/*i==t->d-1时有可能出现*/
i++;
InternalInsert(key,t->p[i]);
if(flag==0)
return;
/*有新键要插入到当前节点中*/
if(t->d<2*M){/*当前节点未满*/
InsInNode(t,i);/*把键值+子树对插入当前节点中*/
flag=0;/*指示上层节点没有需要插入的键值+子树,插入过程结束*/
}
else/*当前节点已满,则分割这个页面并把键值+子树对插入当前节点中*/
SplitNode(t,i);/*继续指示上层节点把返回的键值+子树插入其中*/
}
/*
*把一个键和对应的右子树插入一个节点中
*/
voidInsInNode(btreet,intd)
{
inti;
/*把所有大于要插入的键值的键和对应的右子树右移*/
for(i=t->d;i>d;i--){
t->k[i]=t->k[i-1];
t->v[i]=t->v[i-1];
t->p[i+1]=t->p[i];
}
/*插入键和右子树*/
t->k[i]=InsKey;
t->p[i+1]=NewTree;
t->v[i]=InsValue;
t->d++;
}
/*
*前件是要插入一个键和对应的右子树,并且本节点已经满
*导致分割这个节点,插入键和对应的右子树,
*并向上层返回一个要插入键和对应的右子树
*/
voidSplitNode(btreet,intd)
{
inti,j;
btreetemp;
typekeytemp_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[i];
temp->v[j]=t->v[i];
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[i];
temp->v[j]=t->v[i];
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[i];
temp->v[j]=t->v[i];
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[i]=t->k[i-1]; t->v[i]=t->v[i-1]; t->p[i+1]=t->p[i]; } /*在节点中插入键和右子树*/ 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++; } btreedelete(typekeykey,btreet) { level=btree_level; InternalDelete(key,t); if(t->d==0) /*根节点的子节点合并导致根节点键的数目随之减少, *当根节点中没有键的时候,只有它的最左子树可能非空*/ t=FreeRoot(t); returnt; } voidInternalDelete(typekeykey,btreet) { inti,j,m; btreel,r; intlvl; level--; if(level<0){ Error(0,key);/*在整个树中未找到要删除的键*/ flag=0; return; } for(i=0,j=t->d-1;i (i=m+1): (j=m)); if(key==t->k[i]){/*找到要删除的键*/ if(t->v[i]! =NULL) free(t->v[i]);/*释放这个节点包含的值*/ if(level==0){/*有子树为空则这个键位于叶子节点*/ DelFromNode(t,i); btree_count--; flag=1; /*指示上层节点本子树的键数量减少*/ return; }else{/*这个键位于非叶节点*/ lvl=level-1; /*找到前驱节点*/ r=t->p[i]; while(lvl>0) { r=r->p[r->d]; lvl--; } t->k[i]=r->k[r->d-1]; t->v[i]=r->v[r->d-1]; r->v[r->d-1]=NULL; key=r->k[r->d-1]; } } elseif(key>t->k[i])/*i==t->d-1时有可能出现*/ i++; InternalDelete(key,t->p[i]); /*调整平衡*/ if(flag==0) return; if(t->p[i]->d if(i==t->d)/*在最右子树中发生了删除*/ i--;/*调整最右键的左右子树平衡*/ l=t->p[i]; r=t->p[i+1]; if(r->d>M) MoveLeftNode(t,i); elseif(l->d>M) MoveRightNode(t,i); else{ JoinNode(t,i); /*继续指示上层节点本子树的键数量减少*/ return; } flag=0; /*指示上层节点本子树的键数量没有减少,删除过程结束*/ } } /* *合并一个节点的某个键对应的两个子树 */ voidJoinNode(btreet,intd) { btreel,r; inti,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[i]=r->k[j]; l->v[i]=r->v[j]; l->p[i]=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->k[i]=t->k[i+1]; t->v[i]=t->v[i+1]; t->p[i+1]=t->p[i+2]; } t->d--; node_sum--; } /* *从一个键的右子树向左子树转移一些键,使两个子树平衡 */ voidMoveLeftNode(btreet,intd) { btreel,r; intm;/*应转移的键的数目*/ inti,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[i]=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 实现 语言 描述