码迷,mamicode.com
首页 > 其他好文 > 详细

B-树

时间:2015-09-23 23:10:13      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:

 原地址: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 }

 



 



 

 

  

  

 

B-树

标签:

原文地址:http://www.cnblogs.com/gaot/p/4833795.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!