B-树
在数据结构书上,对于B-树的介绍只有部分算法,有点吃力,百度看到一篇介绍B-树的博文,花了较长的时间理解,还有些生疏,把代码暂存,代码来自http://blog.csdn.net/chenhuijie666/article/details/8662554
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<math.h> 4 #define m 3//B-的阶 5 #define MAX 5//字符串最大长度 6 #define N 16 7 typedef int KeyType; 8 9 struct Others 10 { 11 char info[MAX]; 12 }; 13 14 struct Record 15 { 16 KeyType key;//关键字 17 Others others;//其他部分 18 }; 19 20 typedef struct BTNode{ 21 int keynum;//结点中关键字个数,即结点的大小 22 struct BTNode *parent;//指向双亲结点 23 struct Node 24 { 25 KeyType key;//关键字向量,0号单元未用 26 BTNode *ptr;//子树指针向量 27 Record *recptr;//记录向量指针,0号单元未用 28 }node[m+1]; 29 }BTNode,*BTree;//-树的类型,结点 30 31 typedef struct { 32 BTNode *pt;//指向找到的结点 33 int i;//在结点中的关键字序号 34 int tag;//查找成功标志,0为失败,1为成功 35 }Result;//B-树的查找结果类型 36 37 int InitDSTable(BTree &DT) 38 { 39 DT=NULL; 40 return 1; 41 }//初始化 42 43 void DestroyDSTable(BTree &DT) 44 { 45 int i; 46 if(DT)//非空树 47 { 48 for(i=0;i<=DT->keynum;i++) 49 DestroyDSTable(DT->node[i].ptr); 50 free(DT); 51 DT=NULL; 52 }//if 53 }//销毁 54 55 int Search(BTree p,KeyType k) 56 { 57 //在p->node[1..keynum].key中查找,i使得:p->node[i].key<=k<p->node[i+1].key 58 int i=0,j; 59 for(j=1;j<=p->keynum;j++) 60 if(p->node[j].key<=k) 61 i=j; 62 return i; 63 }//Search 64 65 void Insert(BTree &q,int i,Record *r,BTree ap) 66 { 67 //将r要插入的值和ap分别插入到q->key[i+1]和q->ptr[i+1] 68 int j; 69 for(j=q->keynum;j>i;j--)//空出q->node[i+1] 70 q->node[j+1]=q->node[j]; 71 q->node[j+1].key=r->key; 72 q->node[j+1].ptr=ap; 73 q->node[j+1].recptr=r;//这里是指针,这样肯定有问题,该怎么赋值,这个记录指针到底有什么用呢? 74 q->keynum++; 75 }//Insert 76 77 void NewRoot(BTree &T,Record *r,BTree ap) 78 { 79 //生成含信息(T,r,ap)的新的根结点*T,原T和ap为子树指针 80 BTree p; 81 p=(BTree)malloc(sizeof(BTNode)); 82 p->node[0].ptr=T; 83 T=p; 84 if(T->node[0].ptr) 85 T->node[0].ptr->parent=T; 86 T->parent=NULL; 87 T->keynum=1; 88 T->node[1].key=r->key; 89 T->node[1].recptr=r; 90 T->node[1].ptr=ap; 91 if(T->node[1].ptr) 92 T->node[1].ptr->parent=T; 93 }//NewRoot 94 95 void split(BTree &q,BTree &ap) 96 { 97 //将结点分裂成两个结点,前一半保留,后一半移入新生的结点中ap 98 int i,s=ceil(m/2); 99 ap=(BTree)malloc(sizeof(BTNode));//生成新结点 100 ap->node[0].ptr=q->node[s].ptr; 101 //原来结点中间位置关键字相应指针指向的子树放到新生成结点的0棵子树中 102 for(i=s+1;i<=m;i++)//后一半移入ap 103 { 104 ap->node[i-s]=q->node[i]; 105 if(ap->node[i-s].ptr) 106 ap->node[i-s].ptr->parent=ap; 107 } 108 ap->keynum=m-s; 109 ap->parent=q->parent; 110 q->keynum=s-1;//q的前一半保留,修改keynum 111 }//split 112 113 114 Result SearchBTree(BTree T,int k) 115 { 116 //在m阶B-树T上查找关键字K,返回结果(pt,i,tag).若查找成功,则特征值tag=1,指针pt所指结点中第i个关键字等于K; 117 //否则特征值tag=0,等于K的关键字应插入在指针pt所指结点中的第i和第i+1个关键字之间 118 BTree p,q; 119 bool found; 120 p=T; 121 q=NULL;//q指向p的双亲 122 found=false; 123 Result r; 124 int i=0; 125 while(p&&!found) 126 { 127 i=Search(p,k); 128 if(i>0&&p->node[i].key==k) 129 found=true; 130 else 131 { 132 q=p; 133 p=p->node[i].ptr; 134 } 135 } 136 r.i=i; 137 if(found) 138 // return (p,i,1);//查找成功 139 { 140 r.pt=p; 141 r.tag=1; 142 } 143 else 144 //return (q,i,0); 145 { 146 r.pt=q; 147 r.tag=0; 148 } 149 return r; 150 }//SearchBTree 151 152 void InsertBTree(BTree &T,Record *r,BTree q,int i) 153 { 154 //在m阶B-树T上结点*q的key[i]与key[i+1]之间插入关键字K。 155 //若引起结点过大,则沿双亲链进行必要的结点分裂调整,使T仍是m阶B-树 156 Record *rx;//要插入的值 157 rx=r; 158 int s; 159 BTree ap=NULL; 160 bool finished=false; 161 while(q&&!finished) 162 { 163 Insert(q,i,rx,ap);//将r->key和ap分别插入到q->key[i+1]和q->ptr[i+1],q->recptr[i+1] 164 if(q->keynum<m) 165 finished=true;//插入成功 166 else 167 {//分裂结点*q 168 s=ceil(m/2); 169 rx=q->node[s].recptr; 170 split(q,ap);//将q->key[s+1...m],q->recptr[s+1..m]移入到新结点*ap中 171 q=q->parent; 172 if(q) 173 i=Search(q,rx->key);//在双亲节点*q中查找x的插入位置 174 } 175 }//while 176 if(!finished) 177 NewRoot(T,rx,ap); 178 // return 1; 179 } 180 181 void Deletelt(BTree t,BTNode *dnode,int id) 182 { 183 if(dnode->keynum>=(ceil(m/2))) 184 {//被删关键字K所在的结点的关键字数目不小于ceil(m/2) 185 dnode->keynum--; 186 dnode->node[id].ptr=NULL; 187 } 188 else 189 if((dnode->keynum==(ceil(m/2)-1))&&((id+1)<(m-1))&&(dnode->parent->node[id+1].ptr->keynum>(ceil(m/2)-1))) 190 {// if被删关键字所在结点中的关键字数目等于ceil(m/2)-1,则需调整,本次为右兄弟调整 191 for(int i=1;i<m&&dnode->parent->node[i].key<dnode->parent->node[id+1].ptr->node[1].key;i++) 192 dnode->node[i].key=dnode->parent->node[i].key; 193 dnode->parent->node[1].key=dnode->parent->node[id+1].ptr->node[1].key; 194 (dnode->parent->node[id+1].ptr->keynum)--; 195 } 196 else 197 if((dnode->keynum==((ceil(m/2))-1))&&((id-1)>0)&&dnode->parent->node[id-1].ptr->keynum>((ceil(m/2))-1)) 198 {//被删关键字Ki所在结点的关键字数目等于(ceil(m/2))-1,则需调整。本次为与左兄弟调整 199 for(int i=1;i<m&&dnode->parent->node[i].key > dnode->parent->node[id-1].ptr->node[dnode->parent->node[id-1].ptr->keynum].key;i++) 200 dnode->node[i].key=dnode->parent->node[i].key; 201 dnode->parent->node[1].key=dnode->parent->node[id-1].ptr->node[dnode->parent->node[id-1].ptr->keynum].key; 202 (dnode->parent->node[id-1].ptr->keynum)--; 203 } 204 else 205 if((dnode->keynum==((ceil(m/2))-1))&&((id+1)<(m-1))&&dnode->parent->node[id+1].ptr->keynum==((ceil(m/2))-1)) 206 { 207 do 208 { 209 BTree tmp; 210 tmp=dnode; 211 dnode->parent->node[id+1].ptr->node[2]=dnode->parent->node[id+1].ptr->node[1]; 212 dnode->parent->node[id+1].ptr->node[1]=dnode->parent->node[1]; 213 dnode->parent->node[id+1].ptr->keynum++; 214 dnode->parent->node[id+1].ptr->node[0].ptr=dnode->node[1].ptr; 215 dnode->parent->keynum--; 216 dnode->parent->node[id].ptr=NULL; 217 tmp=dnode; 218 if(dnode->parent->keynum>=((ceil(m/2))-1)) 219 dnode->parent->node[1]=dnode->parent->node[2]; 220 dnode=dnode->parent; 221 free(tmp); 222 }while(dnode->keynum<((ceil(m/2))-1)); //双亲中keynum<ceil(m/2)-1 223 }//3-else if被删关键字Ki所在结点和其相邻兄弟结点中的的关键字数目均等于ceil(m/2)-1,本次假设右兄弟存在 224 else 225 if((dnode->keynum==((ceil(m/2))-1))&&(id-1)>0&&dnode->parent->node[id-1].ptr->keynum==((ceil(m/2))-1)) 226 { 227 do 228 { 229 BTree tmp; 230 tmp=dnode; 231 dnode->parent->node[id-1].ptr->node[2]=dnode->parent->node[id-1].ptr->node[1]; 232 dnode->parent->node[id-1].ptr->node[1]=dnode->parent->node[1]; 233 dnode->parent->node[id-1].ptr->keynum++; 234 dnode->parent->node[id-1].ptr->node[0].ptr=dnode->node[1].ptr; 235 dnode->parent->keynum--; 236 dnode->parent->node[id].ptr=NULL; 237 tmp=dnode; 238 if(dnode->parent->keynum>=((ceil(m/2))-1)) 239 dnode->parent->node[1]=dnode->parent->node[2]; 240 dnode=dnode->parent; 241 free(tmp); 242 }while(dnode->keynum<(ceil(m/2)-1)); //双亲中keynum<((ceil(m/2))-1)) 243 }//4-else if被删关键字Ki所在结点和其相邻兄弟结点中的的关键字数目均等于ceil(m/2)-1,本次假设左兄弟存在 244 else printf("Error!"); //出现异常 245 }//DeleteIt 246 247 void UserDelete(BTree t) 248 { 249 KeyType date; 250 Result s; 251 printf("Please input the date you want to delete:\n"); 252 scanf("%d",&date); 253 s=SearchBTree(t,date); 254 if(!s.tag) printf("Search failed,no such date\n"); 255 else Deletelt(t,s.pt,s.i); 256 }//UserDelete 257 258 void print(BTNode c,int i) // TraverseDSTable()调用的函数 259 { 260 printf("(%d,%s)",c.node[i].key,c.node[i].recptr->others.info); 261 }//print 262 263 void TraverseDSTable(BTree DT,void(*Visit)(BTNode,int)) 264 {// 初始条件: 动态查找表DT存在,Visit是对结点操作的应用函数 265 // 操作结果: 按关键字的顺序对DT的每个结点调用函数Visit()一次且至多一次 266 int i; 267 if(DT) //非空树 268 { 269 if(DT->node[0].ptr) // 有第0棵子树 270 TraverseDSTable(DT->node[0].ptr,Visit); 271 for(i=1;i<=DT->keynum;i++) 272 { 273 Visit(*DT,i); 274 if(DT->node[i].ptr) // 有第i棵子树 275 TraverseDSTable(DT->node[i].ptr,Visit); 276 }//for 277 }//if 278 }//TraverseDSTable 279 280 void InputBR(BTree &t,Record r[]) 281 { 282 Result s; 283 for(int i=0;i<N;i++) 284 { 285 s=SearchBTree(t,r[i].key); 286 if(!s.tag) 287 InsertBTree(t,&r[i],s.pt,s.i); 288 } 289 }//InputBR 290 void UserSearch(BTree t) 291 { 292 int i; 293 Result s; 294 printf("\n请输入待查找记录的关键字: "); 295 scanf("%d",&i); 296 s=SearchBTree(t,i); 297 if(s.tag) 298 print(*(s.pt),s.i); 299 else 300 printf("没找到"); 301 printf("\n"); 302 }//UserSearch 303 304 int main() 305 { 306 Record r[N]={{24,"1"},{45,"2"},{53,"3"},{12,"4"},{37,"5"}, 307 {50,"6"},{61,"7"},{90,"8"},{100,"9"},{70,"10"}, 308 {3,"11"},{30,"12"},{26,"13"},{85,"14"},{3,"15"}, 309 {7,"16"}}; 310 BTree t; 311 InitDSTable(t); 312 InputBR(t,r); 313 printf("按关键字的顺序遍历B_树:\n"); 314 TraverseDSTable(t,print); 315 UserSearch(t); 316 UserDelete(t); 317 TraverseDSTable(t,print); 318 DestroyDSTable(t); 319 return 1; 320 }
Ceil函数的用法,不熟悉,奇怪的是m=3,ceil(m/2)==1,但是自己去测试ceil(1.4)的时候是2,奇怪了,不过自己要明白,删除的时候的判断条件是什么...
ceil 是向离它最近的大整数圆整
如a = [-1.9, -0.2, 3.4, 5.6, 7, 2.4+3.6i]
圆整后:a=[-1,0,4, 6, 7 ,3+4i]
作者:wj704
出处:http://www.cnblogs.com/wj204/