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 }
View Code

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]

posted @ 2013-06-02 22:06  wj704  阅读(194)  评论(0编辑  收藏  举报