标签:
原地址:http://blog.csdn.net/gzj_1101/article/details/48165873
B-tree树即B树,B即Balanced,平衡的意思。因为B树的原英文名称为B-tree,而国内很多人喜欢把B-tree译作B-树,其实,这是个非常不好的直译,很容易让人产生误解。如人们可能会以为B-树是一种树,而B树又是另一种树。而事实上是,B-tree就是指的B树。B-树(百度百科)是由R.Bayer和E.M.McCreight与1972提出的一种多路平衡查找树,当查找的文件较大且存放在直接存取设备中时,能够有效地减少查找过程对文件的读取次数,提高查找效率。
定义:
B-树是一种多路平衡查找树,在文件系统中有所应用。主要用作文件的引索。
一棵m阶的B-树,或为空树,或者满足一下性质。
(1)每棵树只有一个根结点,根结点的关键字的范围[1,m-1];
(2)根结点至少有两颗子树。
(3)每个节点最多有m棵子树。
(4)除根节点和叶子节点外的非终端结点,所有的节点至少有[m/2](向上取整)个子树。
(5)非叶子节点的关键字范围[[m/2]-1,m-1];
(6)所有的叶子节点位于同一层。
(7)节点的关键字个数比子树个数少一。
(8)所有非终端结点包含下列信息
(n,A0,K1,A2,K2,....Kn,An)
其中Ki(i=1,2,3,...n)为关键字且Ki<Ki+1;Ai(i=0,1,2,...n)为指向子树的根结点的指针,且Ki小于Ai所指子树的所有关键字值(换而言之Ki大于Ai-1的所有子树关键字的值)。
下图是典型的3阶B-树
B-树结构定义
typedef struct BTNode{ int keynum; struct BTNode *parent;//父节点 KeyType key[m+1];//关键字 struct BTNode *ptr[m+1];//孩子节点 }BTNode,*BTree;
//辅助的result结构体
typedef struct{ BTNode *pt;//指向要插入的节点 int i;//插入的位置 int tag;//1:查找成功;2:查找失败 }Result;
基本操作:
主要讲解插入和删除操作,查找操作各大教材上面都有,就不在赘述:
1)B-树的插入操作(关键是判断m的关键字个数是否达到上限m-1)
(a)利用查找算法找到插入的位置,若找得到,则说明该关键字,直接返回。否则返回将要插入的结点和位置。
(b)判断该节点是否存在空位置,即判断该节点关键总数n<=m-1;如果满足,则说明该节点还有空位置,则将关键字直接插入该节点中适当的位置。若不满足,则说明该节点已经没有空位置了,需要将该节点分裂成两个。
分裂方法:生成一新节点。将原点上的关键字和K(即要插入的关键字),然后从中间位置将关键字分成两个部分(不包含中间位置关键字),左部分所含关键字放在旧结点中,右部分所含的关键字放在新生成的结点当中,中间关键字连同新生成节点插入到父节点中。如果父节点关键字总数不满足n<=m-1,则重复上述操作,继续向上分裂.
注意:关键字的插入应该先在叶子节点上面操作。即找到合适的叶子节点进行插入操作,而不是在非终端结点上面直接插入。
B-树的删除操作
删除操作的重点是判断该节点的关键字总数是否满足n>=[m/2]-1(后面默认[m/2]表示m/2之后向上取整),根据性质4可得,B-树的删除也主要分为两步。
(a)首先利用B-树的查找算法判断该节点是否为叶子节点。若为叶子节点则根据不同的情况进行相应的操作。
(b)若该节点为非叶子节点,且该节点要删除的关键字为K[i],自在A[i]中找到最小的关键字Y替代K[i],然后在叶子节点中去掉Y;
在B-树的叶子节点中删除一个关键字的方法:
首先将要删除的关键字在叶子节点中删除,然后根据不同的情况作相应的处理。
a.若被删关键字所在节点总数n>=[m/2],则直接删除该节点。
b.若被删关键字所在节点总数n=[m/2]-1,删除之后则不满足B-树的定义,需要对B-树进行调整
调整过程为:如果其左右兄弟结点中有“多余”的关键字,即与该结点相邻的右(左)兄弟结点中的关键字数目大于ceil(m/2)-1。则可将右(左)兄弟结点中最小(大)关键字上移至双亲结点。而将双亲结点中小(大)于该上移关键字的关键字下移至被删关键字所在结点中。
c.如果左右兄弟结点中没有“多余”的关键字,即与该结点相邻的右(左)兄弟结点中的关键字数目均等于ceil(m/2)-1。这种情况比较复杂。需把要删除关键字的结点与其左(或右)兄弟结点以及双亲结点中分割二者的关键字合并成一个结点,即在删除关键字后,该结点中剩余的关键字加指针,加上双亲结点中的关键字Ki一起,合并到Ai(即双亲结点指向该删除关键字结点的左(右)兄弟结点的指针)所指的兄弟结点中去。如果因此使双亲结点中关键字个数小于ceil(m/2)-1,则对此双亲结点做同样处理。以致于可能直到对根结点做这样的处理而使整个树减少一层。
总之,设所删关键字为非终端结点中的Ki,则可以指针Ai所指子树中的最小关键字Y代替Ki,然后在相应结点中删除Y。对任意关键字的删除都可以转化为对最下层关键字的删除。
a、被删关键字Ki所在结点的关键字数目不小于ceil(m/2),则只需从结点中删除Ki和相应指针Ai,树的其它部分不变。
b、被删关键字Ki所在结点的关键字数目等于ceil(m/2)-1,则需调整。调整过程如上面所述。
c、被删关键字Ki所在结点和其相邻兄弟结点中的的关键字数目均等于ceil(m/2)-1,假设该结点有右兄弟,且其右兄弟结点地址由其双亲结点指针Ai所指。则在删除关键字之后,它所在结点的剩余关键字和指针,加上双亲结点中的关键字Ki一起,合并到Ai所指兄弟结点中(若无右兄弟,则合并到左兄弟结点中)。如果因此使双亲结点中的关字数目少于ceil(m/2)-1,则依次类推键.
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 #define m 3 5 #define OK 1 6 #define ERROR 0 7 #define TRUE 1 8 #define FALSE 0 9 10 typedef int Status; 11 typedef int KeyType; 12 13 int Min =m/2+m%2; 14 15 typedef struct BTNode{ 16 int keynum; 17 struct BTNode *parent;//父节点 18 KeyType key[m+1];//关键字 19 struct BTNode *ptr[m+1];//孩子节点 20 }BTNode,*BTree; 21 22 typedef struct{ 23 BTNode *pt;//指向找到的结点 24 int i;//关键字序号 25 int tag;//1:查找成功;2:查找失败 26 }Result; 27 28 Status InitBTree(BTree &bt); 29 int Search(BTree bt,KeyType K); 30 Result& SearchBTree(BTree T,KeyType K); 31 Status Insert(BTree &p,int i,KeyType K,BTree ap); 32 Status split(BTree &p,int s,BTree &ap); 33 Status NewRoot(BTree &T,BTree &q,KeyType K,BTree &ap); 34 Status InsertBTree(BTree &T,KeyType K,BTree q,int i); 35 Status CreateBTree(BTree &bt,KeyType *a,int N); 36 void Successor(BTree &p,int i,BTree &q);// 37 void Remove(BTree &p,int i); 38 void Restore(BTree &p,int i); 39 void MoveRight(BTree &p,int i); 40 void MoveLeft(BTree &p,int i); 41 void Combine(BTree &p,int i); 42 int RecDelete(BTree &p,KeyType K); 43 void DeleteBTree(BTree &p,KeyType K); 44 void PrintBTree(BTree); 45 46 int main() 47 { 48 int N,a[20]; 49 BTree bt=NULL; 50 KeyType K; 51 Result r; 52 printf("元素个数:"); 53 scanf("%d",&N); 54 printf("输入元素序列:"); 55 for(int i=0;i<N;i++) 56 scanf("%d",&a[i]); 57 CreateBTree(bt,a,N); 58 PrintBTree(bt); 59 printf("输入删除关键字:"); 60 scanf("%d",&K); 61 DeleteBTree(bt,K); 62 PrintBTree(bt); 63 64 return 0; 65 } 66 67 Status InitBTree(BTree &bt) 68 { 69 bt->keynum=0; 70 for(int i=0;i<=m;i++) 71 { 72 bt->key[i]=0; 73 bt->ptr[i]=NULL; 74 } 75 bt->parent=NULL; 76 return OK; 77 } 78 79 int Search(BTree bt,KeyType K) 80 { 81 if(K<bt->key[1]) 82 return 0; 83 if(K>=bt->key[bt->keynum]) 84 return bt->keynum; 85 for(int i=1;i<=bt->keynum-1;i++) 86 if(bt->key[i]<=K&&bt->key[i+1]>K) 87 return i; 88 if(bt->keynum==0) 89 return 0; 90 } 91 92 Result& SearchBTree(BTree T,KeyType K) 93 { 94 BTree p=T,q=NULL; 95 Result result; 96 int i=0,found=FALSE; 97 while(p&&!found) 98 { 99 i=Search(p,K); 100 if(i>0&&p->key[i]==K) 101 found=TRUE; 102 else 103 { 104 q=p; 105 p=p->ptr[i]; 106 } 107 } 108 109 result.i=i; 110 if(found==TRUE) 111 { 112 result.pt=p; 113 result.tag=1; 114 }else 115 { 116 result.pt=q; 117 result.tag=0; 118 } 119 return result; 120 } 121 122 Status Insert(BTree &p,int i,KeyType K,BTree ap) 123 { 124 if(i==p->keynum) 125 { 126 p->key[i+1]=K; 127 p->ptr[i+1]=ap; 128 if(ap) 129 ap->parent=p; 130 p->keynum++; 131 } 132 else 133 { 134 p->keynum++; 135 for(int t=p->keynum;t>=i+2;t--) 136 { 137 p->key[t]=p->key[t-1]; 138 p->ptr[t]=p->ptr[t-1]; 139 } 140 p->key[i+1]=K; 141 p->ptr[i+1]=ap; 142 if(ap) 143 ap->parent=p; 144 } 145 146 return OK; 147 } 148 149 Status split(BTree &p,int s,BTree &ap) 150 { 151 int t=0; 152 ap=(BTree)malloc(sizeof(BTNode)); 153 if(!ap) 154 { 155 printf("malloc error"); 156 return ERROR; 157 } 158 InitBTree(ap); 159 for(int i = s + 1; i <= p->keynum; i++) 160 { 161 ap->key[i - s] = p->key[i]; 162 ap->ptr[i - s] = p->ptr[i]; 163 if(ap->ptr[i-s]) 164 ap->ptr[i-s]->parent=ap; 165 } 166 ap->ptr[0]=p->ptr[s]; 167 if(ap->ptr[0]) 168 ap->ptr[0]->parent=ap; 169 ap->keynum=p->keynum-s; 170 //初始化前面的一段内容 171 for(int j=s;j<=p->keynum;j++) 172 { 173 p->key[j]=0; 174 p->ptr[j]=NULL; 175 } 176 p->keynum=s-1; 177 return OK; 178 } 179 180 Status NewRoot(BTree &T,BTree &q,KeyType K, BTree &ap) 181 { 182 int s,i; 183 if(!T)//当根节点为空的之后 184 { 185 T=(BTree)malloc(sizeof(BTNode)); 186 if(!T)return ERROR; 187 InitBTree(T); 188 T->key[1]=K; 189 T->keynum++; 190 } 191 else//返回到最上面的顶点 192 { 193 s=T->keynum/2+T->keynum%2; 194 q=(BTree)malloc(sizeof(BTNode)); 195 if(!q)return ERROR; 196 InitBTree(q); 197 q->key[1]=K; 198 q->ptr[0]=T; 199 q->ptr[1]=ap; 200 q->keynum++; 201 T->parent=q; 202 if(ap) 203 ap->parent=q; 204 T=q; 205 } 206 return OK; 207 } 208 209 Status InsertBTree(BTree &T,KeyType K,BTree q,int i) 210 { 211 KeyType x=K; 212 BTree ap=NULL; 213 int finished=FALSE; 214 int s; 215 216 while(q&&!finished) 217 { 218 Insert(q,i,x,ap); 219 if(q->keynum<m) 220 finished=TRUE; 221 else 222 { 223 s=m/2+m%2; 224 x=q->key[s]; 225 split(q,s,ap); 226 q=q->parent; 227 if(q) 228 i=Search(q,x); 229 } 230 } 231 if(!finished)//分裂到最高结点,或者T为空树 232 NewRoot(T,q,x,ap); 233 return OK; 234 } 235 236 //创建一个B-Tree 237 Status CreateBTree(BTree &bt,KeyType *a,int N) 238 { 239 Result result; 240 for(int i=0;i<N;i++) 241 { 242 result=SearchBTree(bt,a[i]); 243 if(!result.tag)//B-Tree中没有该节点,插入 244 InsertBTree(bt,a[i],result.pt,result.i); 245 } 246 return OK; 247 } 248 249 void PrintBTree(BTree bt) 250 { 251 if(bt) 252 { 253 for(int i=1;i<=bt->keynum;i++) 254 printf("%d ",bt->key[i]); 255 printf("\n"); 256 for(int t=0;t<=bt->keynum;t++) 257 PrintBTree(bt->ptr[t]); 258 } 259 } 260 261 void DeleteBTree(BTree &bt,KeyType K) 262 { 263 BTree p; 264 if(RecDelete(bt,K)==0) 265 printf("关键字%d不在B-树中\n",K); 266 else 267 { 268 printf("删除成功!\n"); 269 if(bt->keynum==0) 270 { 271 p=bt; 272 bt=bt->ptr[0]; 273 free(p); 274 } 275 } 276 } 277 278 int RecDelete(BTree &p,KeyType K) 279 { 280 int i,j,found; 281 BTree q,t=NULL,s; 282 Result r; 283 KeyType P; 284 if(p==NULL) 285 return 0; 286 else 287 { 288 r=SearchBTree(p,K); 289 i=r.i; 290 q=r.pt; 291 if(r.tag==1)//找到了该节点 292 { 293 if(q->ptr[i-1])//该节点为非叶子节点 294 { 295 Successor(q,i,t);//将该节点删除后,从q.ptr[i]中将最小的位置给他 296 P=t->key[1]; 297 Remove(t,1); 298 if(t->keynum<Min-1) 299 { 300 j=Search(t->parent,P); 301 Restore(t->parent,j); 302 } 303 304 } 305 else 306 { 307 t=q->parent; 308 j=Search(t,K); 309 Remove(q,i);//删除叶子节点中的关键字 310 if(q->keynum<Min-1) 311 Restore(t,j); 312 } 313 } 314 } 315 return r.tag; 316 } 317 318 void Successor(BTree &p,int i,BTree &q) 319 { 320 BTree t; 321 for(q=p->ptr[i];q!=NULL;t=q,q=q->ptr[0]) 322 p->key[i]=q->key[1]; 323 q=t; 324 } 325 326 void Remove(BTree &p,int i) 327 { 328 for(int j=i;j<=p->keynum;j++) 329 { 330 p->key[i]=p->key[i+1]; 331 p->ptr[i]=p->ptr[i+1]; 332 } 333 p->key[p->keynum]=0; 334 p->ptr[p->keynum]=NULL; 335 --p->keynum; 336 } 337 338 void Restore(BTree &p,int i) 339 { 340 //shan删除关键字后,调整整个B- 341 if(i==0) 342 { 343 if(p->ptr[1]->keynum>Min-1) 344 MoveLeft(p,i); 345 else 346 Combine(p,1); 347 } 348 else if(i==p->keynum) 349 { 350 if(p->ptr[p->keynum-1]->keynum>Min-1) 351 MoveRight(p,i); 352 else 353 Combine(p,p->keynum); 354 } 355 else//其他情况即为既有左子树,又有右子树 356 { 357 if(p->ptr[i+1]->keynum>Min-1) 358 MoveLeft(p,i); 359 else if(p->ptr[i-1]->keynum>Min-1) 360 MoveRight(p,i); 361 else 362 Combine(p,i); 363 } 364 365 } 366 367 void MoveRight(BTree &p,int i) 368 { 369 BTree q; 370 q=p->ptr[i]; 371 q->keynum++; 372 for(int t=q->keynum;t>=2;t--) 373 { 374 q->key[t]=q->key[t-1]; 375 q->ptr[t]=q=q->ptr[t-1]; 376 } 377 q->ptr[1]=q->ptr[0]; 378 q->key[1]=p->key[i]; 379 q=p->ptr[i-1]; 380 p->key[i]=q->key[q->keynum]; 381 q->key[q->keynum]=0; 382 q->ptr[q->keynum]=NULL; 383 q->keynum--; 384 } 385 386 void MoveLeft(BTree &p,int i) 387 { 388 BTree q; 389 q=p->ptr[i]; 390 q->keynum++; 391 q->key[q->keynum]=p->key[i+1]; 392 q=p->ptr[i+1]; 393 p->key[i+1]=q->key[1]; 394 for(int t=1;t<=q->keynum-1;t++) 395 { 396 q->key[t]=q->key[t+1]; 397 q->ptr[t]=q->ptr[t+1]; 398 } 399 q->key[q->keynum]=0; 400 q->keynum--; 401 } 402 403 void Combine(BTree &p,int i) 404 { 405 int c; 406 BTree q; 407 BTree l; 408 q=p->ptr[i]; 409 l=p->ptr[i-1]; 410 l->keynum++; 411 l->key[l->keynum]=p->key[i]; 412 //合并两个叶子节点 413 for(c=l->keynum+1;c<=l->keynum+q->keynum;c++) 414 l->key[c]=q->key[c-l->keynum]; 415 l->keynum+=q->keynum; 416 //删除父节点中分割的关键字 417 for(c=i;c<=p->keynum-1;c++) 418 { 419 p->key[c]=p->key[c+1]; 420 p->ptr[c]=p->ptr[c+1]; 421 } 422 p->key[p->keynum]=0; 423 p->ptr[p->keynum]=NULL; 424 p->keynum--; 425 free(q); 426 }
标签:
原文地址:http://www.cnblogs.com/gaot/p/4833795.html