B+树的代码实现.docx
- 文档编号:29771672
- 上传时间:2023-07-26
- 格式:DOCX
- 页数:22
- 大小:19.42KB
B+树的代码实现.docx
《B+树的代码实现.docx》由会员分享,可在线阅读,更多相关《B+树的代码实现.docx(22页珍藏版)》请在冰豆网上搜索。
B+树的代码实现
B+树的实现。
这个B+树是建立在操作系统的文件系统之上的,并没有自己的文件系统。
B+树的节点全部存储在一个文件中。
由于每个节点的大小是相同的,所以我对每个节点
进行编号,即每个节点的id。
这样每个节点在文件的字节位置就可以通过计算sizeof(BPNode)*(c->id-1)得到。
所以,每个B+树的节点有一个id属性,就是记录自己的标号。
同时对B+树建立一个结构体,这个结构体中的root属性,用于指向读入内存后的树的根节点。
locate属性记录树的根节点的在文件中的标号。
num属性记录这棵树的节点个数,每次新增一个节点都会加一。
name属性记录用于存储这个B+树的文件名(相对cpp文件所在的文件夹),fp属性用于记录打开这个文件时的文件指针
因为这个文件只记录B+树的节点,所以每次插入的时候只需要直接插入最后(只有num个节点,同时新插入的节点的id是num+1)
暂时不考虑删除节点的文件空间回收。
打开文件是要注意打开模式,r+模式可以才可以随意用fseek()定位之后,读或写。
fseek()和fread()和fwrite()是用于二进制打开的文件,如果文本模式打开,可能出现问题,如:
覆盖。
#include
#include
#include
#include
#defineT3//b+树的度数
#defineKeyTypeint
#definePointerint
//节点结构体
typedefstructBPNode
{
unsignedintid;//记录这个节点在文件的中的编号
unsignedintn;//记录这个节点有多少个关键字
intleaf;//判断是否为页节点
KeyTypekey[2*T];//关键字(及对应每个孩子节点的中关键字最小的关键字)
Pointerchild[2*T];//指针,记录每个孩子在文件的第几个位置
Pointernext;//指针,,记录下一个兄弟
}BPNode,*P_BPNode;
//树的结构体
typedefstructBPTree
{
P_BPNoderoot;
unsignedintlocate;//记录根节点的在文件中的标号,即id
unsignedintnum;//记录更有多少个节点
charname[100];//用于存储B+树的节点文件的名字
FILE*fp;//打开写入name文件时,使用
intstart;//最小的数据所在的叶节点
}BPTree,*P_BPTree;
BPTreeindexBPTree;//全局变量,b+树
intwriteNode(P_BPNodew)
{
fseek(indexBPTree.fp,sizeof(BPNode)*(w->id-1)+2*sizeof(int),SEEK_SET);
fwrite(w,sizeof(BPNode),1,indexBPTree.fp);
return0;
}
intreadNode(P_BPNoder,Pointerid)
{
fseek(indexBPTree.fp,(sizeof(BPNode))*(id-1)+2*sizeof(int),SEEK_SET);
fread(r,(sizeof(BPNode)),1,indexBPTree.fp);
return0;
}
intpNode(P_BPNoden);
intcreateIndexBPTree(char*tableName,char*attr)
{//创建B+树,并进行相应的初始化,B+树的结构体是一个全局变量。
P_BPNoderoot;
indexBPTree.root=(P_BPNode)malloc(sizeof(BPNode));
indexBPTree.num=1;
indexBPTree.start=1;
memcpy(indexBPTree.name,".\\table\\",sizeof(".\\table\\"));
strcat(indexBPTree.name,tableName);
strcat(indexBPTree.name,".");
strcat(indexBPTree.name,attr);
puts(indexBPTree.name);
root=indexBPTree.root;
root->n=0;
root->leaf=1;
root->next=-1;
root->id=1;
indexBPTree.locate=1;
indexBPTree.fp=fopen(indexBPTree.name,"wb");
fwrite(&indexBPTree.num,sizeof(int),1,indexBPTree.fp);
fwrite(&indexBPTree.locate,sizeof(int),1,indexBPTree.fp);
writeNode(root);
fclose(indexBPTree.fp);
/*
printf("原始:
%d\n",indexBPTree.root->next);
memset(indexBPTree.root,0,sizeof(BPNode));
printf("memset后:
%d\n",indexBPTree.root->next);
indexBPTree.fp=fopen(indexBPTree.name,"r");
fread(indexBPTree.root,sizeof(BPNode),1,indexBPTree.fp);
fclose(indexBPTree.fp);
printf("读取文件后:
%d\n",indexBPTree.root->next);
*/
free(root);
indexBPTree.root=NULL;
return0;
}
intsplitBPNode(P_BPNodep,P_BPNodec,inti)
{//节点的分裂,要求p节点至少还能插入一个节点,c节点是满的,即n为2*T;
intj;
P_BPNodeb;
b=(P_BPNode)malloc(sizeof(BPNode));
b->leaf=c->leaf;
b->n=T;
b->id=indexBPTree.num+1;//为b赋值id号,用于表示该节点,,同时id号就是这个节点在文件的位置
b->next=c->next;//为b的next赋值,即原来的c节点的next
//将c节点的后半部分关键字复制给b
for(j=0;j { b->key[j]=c->key[j+T]; b->child[j]=c->child[j+T]; } //至此b节点的对应元素已经建立好了,但还需要写入文件 indexBPTree.num++; c->n=T;//c节点的关键字数目减半 c->next=b->id; //将p节点的i之后的节点后移 for(j=p->n-1;j>i;j--) { p->key[j+1]=p->key[j]; p->child[j+1]=p->child[j]; } //将b节点插入p中 p->key[i+1]=b->key[0]; p->child[i+1]=b->id; p->n++;//p关键字个数加一 //写入p writeNode(p); writeNode(c); writeNode(b); free(b); return0; }//splitBPNode intinsertBPNodeNotFull(P_BPNodes,KeyTypek,unsignedintid){//插入,要求s节点不是满的 inti=s->n-1; if(s->leaf) {//叶节点,找的合适的位置 while(i>=0&&s->key[i]>k) { s->key[i+1]=s->key[i]; s->child[i+1]=s->child[i]; i--; } s->key[i+1]=k; s->child[i+1]=id; s->n++; writeNode(s); } else { P_BPNodetmp=(P_BPNode)malloc(sizeof(BPNode)); while(i>=0&&s->key[i]>k) { i--; } if(i<0) {//插入的元素最小,则把这个元素插入第一个节点,并修改对应的keyi++; s->key[i]=k; } writeNode(s); readNode(tmp,s->child[i]);//读取对应的 if(tmp->n==2*T) { splitBPNode(s,tmp,i); if(k>s->key[i+1]) i++; readNode(tmp,s->child[i]);//重新读取,,有待优化 } insertBPNodeNotFull(tmp,k,id); free(tmp); } return0; } PointerequalSearch(P_BPTreetree,KeyTypek) {//等值查询,给出key值,查找对应的id,并返回。 如果不存在该节点,返回一个负数inti; intresult; P_BPNoder; r=tree->root; if(k return-1; P_BPNodetmp=(P_BPNode)malloc(sizeof(BPNode)); while (1) { i=r->n-1; while(i>=0&&r->key[i]>k) i--; if(r->leaf)//是叶子,结束 break; readNode(tmp,r->child[i]); r=tmp; }//while if(r->key[i] return-1; result=r->child[i]; free(tmp); tmp=NULL; returnresult; }//equalSearch intrangeSearch(P_BPTreetree,KeyTypelow,KeyTypehigh) {//范围查找,key值大于等于low,小于等于high。 返回范围内的个数,unsignedinti; P_BPNoder=tree->root; Pointer*result; P_BPNodetmp=(P_BPNode)malloc(sizeof(BPNode)); if(high return0; if(high return0; if(low low=r->key[0]; while (1) { i=r->n-1; while(i>=0&&r->key[i]>low) i--; if(r->leaf)//是叶子,结束 break; readNode(tmp,r->child[i]); r=tmp; }//while if(r->key[i] i++; unsignedintnum=100; result=(Pointer*)malloc(sizeof(Pointer)*num); unsignedintj=0; while (1) { for(;i { if(j>=num) { num+=100; realloc(result,sizeof(Pointer)*num); } result[j++]=r->child[i]; //printf("sid: %diid: %did: %d\n",r->key[i],r->id,r->child[i]); } if(i break; readNode(tmp,r->next); r=tmp; i=0; }//while free(tmp); tmp=NULL; returnj; }//rangeSearch intinsertKeyInBPTree(P_BPTreetree,KeyTypek,Pointerid) {//向树中插入节点 P_BPNoder=tree->root; if(equalSearch(tree,k)>0) { printf("元素已存在! "); return-1; } if(tree->root->n==2*T) {//根节点满了,重新分配根节点,并进行初始化 P_BPNodes=(P_BPNode)malloc(sizeof(BPNode)); s->leaf=0; s->n=1; s->key[0]=r->key[0]; s->child[0]=r->id; s->id=tree->num+1; s->next=-1; //将新的根写入磁盘 writeNode(s); tree->num++; writeNode(r); splitBPNode(s,r,0); //根变为s,所以将新根copy到tree->root指针所指向的内存。 (tree->root将一直指向一片开辟了的内存,且时刻保存树根的整个节点) memcpy(tree->root,s,sizeof(BPNode)); tree->locate=s->id; insertBPNodeNotFull(s,k,id); free(s);//释放内存 } else insertBPNodeNotFull(r,k,id); return0; }//insertBPNode intinitIndexBPTree(char*tableName,char*attr) {//初始化BPTree,打开相应文件,fp记录;为root分配内存可以存储一个节点的内存,并读入根节点 indexBPTree.root=(P_BPNode)malloc(sizeof(BPNode)); indexBPTree.start=1; memcpy(indexBPTree.name,".\\table\\",sizeof(".\\table\\")); strcat(indexBPTree.name,tableName); strcat(indexBPTree.name,"."); strcat(indexBPTree.name,attr); indexBPTree.fp=fopen(indexBPTree.name,"rb+"); fread(&indexBPTree.num,sizeof(int),1,indexBPTree.fp); fread(&indexBPTree.locate,sizeof(int),1,indexBPTree.fp); readNode(indexBPTree.root,indexBPTree.locate); return0; } intendBPTree() {//将建立的树结束 fseek(indexBPTree.fp,0,SEEK_SET); fwrite(&indexBPTree.num,sizeof(int),1,indexBPTree.fp); fwrite(&indexBPTree.locate,sizeof(int),1,indexBPTree.fp); free(indexBPTree.root); fclose(indexBPTree.fp); return0; } intpNode(P_BPNoden) {//输出节点 printf("%sid: %dnext: %d个数: %d\n",n->leaf? "是叶节点": "不是叶节点",n->id,n->next,n->n); for(unsignedinti=0;i printf("key[%d]: %d\t",i,n->key[i]); puts(""); for(i=0;i printf("child[%d]: %d\t",i,n->child[i]); puts(""); return0; }//pNode intreplaceKeyInBPTree(P_BPTreetree,KeyTypeoldkey,KeyTypenewkey) {//将oldkey替换为newkey P_BPNoder=tree->root; inti; P_BPNodetmp=(P_BPNode)malloc(sizeof(BPNode)); while (1) { i=r->n-1; while(i>=0&&r->key[i]>oldkey) i--; if(r->key[i]==oldkey) { r->key[i]=newkey; writeNode(r); } if(r->leaf) break; readNode(tmp,r->child[i]); r=tmp; } free(tmp); return0; } intadjustToDel(P_BPNodep,P_BPNodex,unsignedinti){//p指向x的父节点,i指的是,x是p的下标 unsignedintj; P_BPNodeleft=NULL; P_BPNoderight=NULL; P_BPNodetmp=(P_BPNode)malloc(sizeof(BPNode)); if(i>0)//x有左兄弟 { readNode(tmp,p->child[i-1]); left=tmp; if(left->n>T) { for(j=x->n;j>0;j--) { x->key[j]=x->key[j-1]; x->child[j]=x->child[j-1]; } x->n++; x->key[0]=left->key[left->n-1]; x->child[0]=left->child[left->n-1]; writeNode(x); left->n--; writeNode(left); p->key[i]=x->key[0]; writeNode(p); return0; } }//if if(i { readNode(tmp,p->child[i+1]); right=tmp; left=NULL; if(right->n>T) { x->key[x->n]=right->key[0]; x->child[x->n]=right->child[0]; x->n++; writeNode(x); for(j=0;j { right->key[j]=right->key[j+1]; right->child[j]=right->child[j+1]; } right->n--; writeNode(right); p->key[i+1]=right->key[0]; writeNode(p); return0; } } if(left==tmp) { for(j=0;j { left->key[T+j]=x->key[j]; left->child[T+j]=x->child[j]; } left->n+=T; left->next=x->next; writeNode(left); for(j=i;j { p->key[j]=p->key[j+1]; p->child[j]=p->child[j+1]; } p->n--; writeNode(p); memcpy(x,left,sizeof(BPNode)); } else { for(j=0;j { x->key[T+j]=right->key[j]; x->child[T+j]=right->child[j]; } x->n+=T; x->next=right->next; writeNode(x); for(j=i+1;j { p->key[j]=p->key[j+1]; p->child[j]=p->child[j+1]; } p->n--; writeNode(p); } free(tmp); left=right=tmp=NULL; return0; } //调用这个函数是,参数节点p,必须满足相应的要求: //①如果p是根节点且是叶子节点,则没有要求 //②如果p是根节点(非叶),则p节点的子节点个数不小于2(B+树
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 代码 实现