数据结构课程实践--B树

坑坑爹爹连改带抄的把代码坑了出来

View Code
  1 #include <stdio.h>
  2 #include <malloc.h>
  3 #include <queue>
  4 #include <Windows.h>
  5 const int MAX = 10;
  6 typedef int KeyType ;
  7 typedef struct Node{
  8     int keynum;//关键字数目
  9     KeyType key[MAX];//关键字  由1开始
 10     Node *parent;
 11     Node *child[MAX];
 12 }BTree;
 13 
 14 typedef struct Node2{
 15     BTree *result;//找到的节点
 16     int flag;//判断查找是否成功
 17     int num;//找到的位置
 18 }Result;
 19 
 20 struct QueueNode{
 21     BTree *p;
 22     int step;
 23 };
 24 int m;//阶数
 25 int max;//最大关键字数  max = m - 1
 26 int min;//最小关键字数    min = (m - 1)/2
 27 
 28 /*查找函数: 1.搜索结点Q,找k的位置或者k应该插入的位置*/
 29 int Search(BTree *Q,KeyType k)
 30 {
 31     int i;
 32     for(i=0;i<Q->keynum;i++)
 33     {
 34         if(Q->key[i+1] > k)
 35         {
 36             break;
 37         }
 38     }
 39     return i;
 40 }
 41 /*查找函数: 2.搜索树T,查找成功则跳出循环,查找不成功则向下一层查找,直到最底层*/
 42 Result SearchBTree(BTree *T,KeyType k)
 43 {
 44     int i=0;
 45     BTree *p = T;
 46     BTree *q = NULL;
 47     Result Re;
 48     int found = 0;
 49 
 50     while(p!=NULL)
 51     {
 52         i = Search(p,k);
 53         if(i>0 && p->key[i] == k)
 54         {
 55             found = 1;
 56             break;
 57         }
 58         else
 59         {
 60             q = p;//保存父节点
 61             p = p->child[i];
 62         }
 63     }
 64 
 65     Re.num = i;
 66     if(found == 1)//查找成功返回当前位置
 67     {
 68         Re.flag = 1;
 69         Re.result = p;
 70     }
 71     else//查找失败返回父节点位置
 72     {
 73         Re.flag = 0;
 74         Re.result = q;
 75     }
 76     return Re;
 77 }
 78 
 79 
 80 /*插入函数: 3.在结点Q中的第 i+1 位置插入关键字为k 和 子树mid*/
 81 void Insert(BTree *Q,KeyType k,int i,BTree *mid)
 82 {
 83     int j;
 84     for(j=Q->keynum;j>i;j--)
 85     {
 86         Q->key[j+1] = Q->key[j];
 87         Q->child[j+1] = Q->child[j];
 88     }
 89     Q->key[i+1] = k;
 90     Q->child[i+1] = mid;
 91     if(mid!=NULL)
 92     {
 93         mid->parent = Q;
 94     }
 95     Q->keynum++;
 96 }
 97 /*插入函数: 4.分裂结点
 98 左子树为原来的结点,不需要做多余的操作.
 99 右子树为新申请的结点,没有与父结点相连.
100 且中间的数值还没有插入到父结点中,所以要结合插入操作.
101 */
102 void Split(BTree *Q,BTree **mid)
103 {
104     int sum = (m+1)/2;
105     (*mid) = (BTree*)malloc(sizeof(BTree));
106 
107     (*mid)->keynum = Q->keynum - sum;//新的结点的关键字数
108     Q->keynum = sum-1;//旧结点关键字数
109     (*mid)->parent = Q->parent ;//有相同的父结点
110 
111     int i;
112     (*mid)->child[0] = Q->child[sum];//新结点第0个子树做特殊处理
113     for(i=sum+1;i<=m;i++)
114     {
115         (*mid)->child[i-sum] = Q->child[i];
116         (*mid)->key[i-sum] = Q->key[i];
117     }
118     for(i=0;i<(*mid)->keynum;i++)//修改父结点
119     {
120         if((*mid)->child[i]!=NULL)
121         {
122             (*mid)->child[i]->parent = (*mid);
123         }
124     }
125 }
126 /*插入函数: 5.建立新的根结点*/
127 void SetRoot(BTree **T,BTree *Q,KeyType k,BTree *mid)
128 {
129     (*T) = (BTree*) malloc (sizeof(BTree));
130     (*T)->child[0] = Q;//左子树
131     (*T)->child[1] = mid;//右子树
132     (*T)->key[1] = k;//关键字
133     (*T)->keynum = 1;//关键字数目
134     (*T)->parent = NULL;//父结点
135     if(Q!=NULL)
136     {
137         Q->parent = (*T);
138     }
139     if(mid!=NULL)
140     {
141         mid->parent = (*T);
142     }
143 }
144 /*插入函数: 6.在树T中插入k,若插入后实得节点过大则要分裂结点,调整B树的结构*/
145 void InsertBTree(BTree **T,KeyType k,int i,BTree *result)
146 {
147     if(result == NULL)//如果result为NULL  则为空树
148     {
149         SetRoot(T,NULL,k,NULL);
150     }
151     else
152     {
153         BTree *mid = NULL;
154         int NewRoot = 0;
155         while(NewRoot == 0)//一直循环直到发现未满或者发现需要新的根节点为止
156         {
157             Insert(result,k,i,mid);
158             if(result->keynum <= max)//未满  则结束
159             {
160                 break;
161             }
162             else//已满 分裂结点
163             {
164                 Split(result,&mid);
165                 int sum = (m+1)/2;
166                 k = result->key[sum];
167                 if(result->parent != NULL)
168                 {
169                     result = result->parent;
170                     i = Search(result,k);
171                 }
172                 else
173                 {
174                     NewRoot = 1;
175                     SetRoot(T,result,k,mid);
176                 }
177             }
178         }
179     }
180 }
181 
182 /*删除函数:7.在结点Q中删除关键字和孩子指针*/
183 void DeleteKey(BTree *Q,int num)
184 {
185     int i;
186     for(i=num+1;i <= Q->keynum ; i++)
187     {
188         Q->key[i-1] = Q->key[i];
189         Q->child[i-1] = Q->child[i];
190     }
191     Q->keynum--;
192 }
193 
194 /*删除函数:8.查找被删除结点的替代结点并把替代结点替代白删除结点——查找该节点右子树的最小值*/
195 void Replace(BTree *Q,int num)
196 {
197     BTree *mid = Q->child[num];
198     while(mid->child[0]!=NULL)
199     {
200         mid = mid->child[0];
201     }
202     Q->key[num] = mid->key[1]; //改变关键字
203 }
204 
205 /*删除函数:9.把一个关键字移动的右兄弟中*/
206 void MoveRight(BTree *Q,int num)//传入的Q为不符合的结点的父结点
207 {
208     int i;
209     BTree *mid = Q->child[num];
210     for(i=mid->keynum;i>0;i--)
211     {
212         mid->key[i+1] = mid->key[i];
213         mid->child[i+1] = mid->child[i];
214     }
215     mid->child[1] = mid->child[0];//把关键字从父结点移动到右子节点
216     mid->key[1] = Q->key[num];
217     mid->keynum++;
218 
219     mid = Q->child[num-1];//把关键字从左子节点移到双亲结点
220     Q->key[num] = mid->key[mid->keynum];
221     Q->child[num]->child[0] = mid->child[mid->keynum];
222     mid->keynum--;
223 }
224 
225 /*删除函数:10.把一个关键字移动的左兄弟中*/
226 void MoveLeft(BTree *Q,int num)
227 {
228     int i;
229     BTree *mid = Q->child[num-1];
230     mid->keynum++;//把关键字从父结点移动到左子节点
231     mid->key[mid->keynum] = Q->key[num];
232     mid->child[mid->keynum] = Q->child[num]->child[0];
233 
234     mid = Q->child[num];//把关键字从右子节点移到双亲结点
235     Q->key[num] = mid->key[1];
236 
237     mid->child[0] = mid->child[1];
238     for(i=1;i<mid->keynum;i++)
239     {
240         mid->key[i] = mid->key[i+1];
241         mid->child[i] = mid->child[i+1];
242     }
243     mid->keynum--;
244 }
245 
246 /*删除函数:11.合并父结点中的一个关键字和左右子节点*/
247 void Combine(BTree *Q,int num)
248 {
249     int i;
250     BTree *left = Q->child[num-1];
251     BTree *right = Q->child[num];//指向右子节点,他将被删除.
252     left->keynum++;
253     left->key[left->keynum] = Q->key[num];
254     left->child[left->keynum] = right->child[0];
255     for(i=1;i<=right->keynum;i++)
256     {
257         left->keynum++;
258         left->key[left->keynum] = right->key[i];
259         left->child[left->keynum] = right->child[i];
260     }
261 
262     for(i=num ; i<Q->keynum ; i++)
263     {
264         Q->key[i] = Q->key[i+1];
265         Q->child[i] = Q->child[i+1];
266     }
267     Q->keynum--;
268     free(right);
269 }
270 
271 /*删除函数:12.判断B树是否需要调整和要调整的结点所在的位置*/
272 void Judge(BTree *Q,int num)
273 {
274     if(num == 0)//最左边
275     {
276         if(Q->child[1]->keynum > min)
277         {
278             MoveLeft(Q,1);
279         }
280         else
281         {
282             Combine(Q,1);
283         }
284     }
285     else
286     {
287         if(num == Q->keynum)//最右边
288         {
289             if(Q->child[num-1]->keynum > min)
290             {
291                 MoveRight(Q,num);
292             }
293             else
294             {
295                 Combine(Q,num);
296             }
297         }
298         else
299         {
300             if(Q->child[num]->keynum > min)
301             {
302                 MoveLeft(Q,num);
303             }
304             else
305             {
306                 if(Q->child[num-1]->keynum > min)
307                 {
308                     MoveRight(Q,num);
309                 }
310                 else
311                 {
312                     Combine(Q,num);
313                 }
314             }
315         }
316     }
317 }
318 
319 /*删除函数:13.搜索要删除的函数在不在B树中,查找成功返回1,不成功返回0,且调整num的位置*/
320 int SearchNode(BTree *Q,KeyType k,int *num)
321 {
322     int i;
323     for(i=1;i <= Q->keynum ;i++)
324     {
325         if(Q->key[i] == k)
326         {
327             *num = i;
328             return 1;
329         }
330         else
331         {
332             if(Q->key[i] > k)
333             {
334                 *num = i-1;
335                 return 0;
336             }
337         }
338     }
339     *num = i-1;
340     return 0;
341 }
342 
343 /*删除函数:14.删除关键字以及调整B树结构*/
344 int DeleteNode(BTree *Q,KeyType k)
345 {
346     int num;
347     int found;
348     if(Q==NULL)
349     {
350         return 0;
351     }
352     else
353     {
354         found = SearchNode(Q,k,&num);
355         if(found == 1)
356         {
357             if(Q->child[num] != NULL)//判断是否为叶子结点
358             {
359                 Replace(Q,num);//寻找Q的右子树中的最小值代替他,完后后Q->key[num]变为代替的值
360                 DeleteNode(Q->child[num],Q->key[num]);
361             }
362             else
363             {
364                 DeleteKey(Q,num);
365             }
366         }
367         else
368         {
369             found = DeleteNode(Q->child[num],k);
370         }
371 
372         if(Q->child[num] != NULL)
373         {
374             if(Q->child[num]->keynum < min)
375             {
376                 Judge(Q,num);
377             }
378         }
379         return found;
380     }
381 }
382 
383 /*删除函数:15.在B树中删除关键字,由于删除时只在右子树删除,所以若右子树没有其他元素则将他删除*/
384 void DeleteBTree(BTree **T,KeyType k)
385 {
386     BTree *mid;
387     if(DeleteNode(*T,k) == 0)
388     {
389         printf("错误!!关键字不在B树中\n");
390     }
391     else
392     {
393         if((*T)->keynum == 0)
394         {
395             mid = (*T);
396             (*T) = (*T)->child[0];
397             free(mid);
398         }
399     }
400 }
401 
402 /*输出函数:16.*/
403 void Print(BTree *T)
404 {
405     std::queue <QueueNode> q;
406     if(T != NULL)
407     {
408         QueueNode mid;
409         mid.p = T;
410         mid.step = 1;
411         q.push(mid);
412         int step = 1;
413         while(!q.empty())
414         {
415             int i;
416             mid = q.front();
417             q.pop ();
418             if(mid.step != step)
419             {
420                 printf("\n");
421                 step++;
422             }
423             printf("[");
424             for(i=1; i<=mid.p->keynum ; i++)
425             {
426                 printf(" %d",mid.p->key[i]);
427             }
428             printf(" ] ");
429 
430             for(i=0 ; i<=mid.p->keynum; i++)
431             {
432                 QueueNode put;
433                 put.p = mid.p->child[i];
434                 put.step = mid.step + 1;
435                 if(put.p != NULL)
436                 {
437                     q.push(put);
438                 }
439             }
440         }
441     }
442 }
443 
444 
445 int main()
446 {
447     //KeyType num[1100] = {4,9,0,1,8,6,3,5,2,7};
448     KeyType num;
449     m=3;
450     max = m-1;
451     min = (m-1)/2;
452     int i;
453     BTree *T = NULL;
454     while(1)
455     {
456         printf("请输入要创建B树阶数:");
457         scanf("%d",&m);
458         if(m>2)
459         {
460             break;
461         }
462         else
463         {
464             printf("错误!!B树阶数应该大于2\n");
465         }
466     }
467     printf("\n");
468     printf("创建一棵%d阶B树:\n\n",m);
469     while(1)
470     {
471         printf("请选择需要的操作:\n");
472         printf("插入操作--1    删除操作--2    退出--0\n");
473         int n;
474         scanf("%d",&n);
475         switch(n)
476         {
477         case 1:
478             system("CLS");
479             Result s;
480             printf("请输入要插入的数字: ");
481             scanf("%d",&num);
482             printf("将%d插入B树:\n",num);
483             s =  SearchBTree(T,num);
484             if(s.flag == 0)
485             {
486                 InsertBTree(&T,num,s.num,s.result);
487                 Print(T);
488                 printf("\n\n");
489             }
490             else
491             {
492                 printf("错误!! 插入的数%d在已在B树中\n\n",num);
493             }
494             break;
495         case 2:
496             system("CLS");
497             printf("删除操作:\n");
498             printf("请输入要删除的数字: ");
499             scanf("%d",&num);
500             printf("\n");
501                 printf("删除%d:\n",num);
502                 DeleteBTree(&T,num);
503                 Print(T);
504                 printf("\n\n");
505             break;
506         case 0:
507             return 0;
508         default:
509             printf("输入错误\n");
510         }
511     }
512     return 0;
513 }

 

posted @ 2012-11-07 18:31  zx雄  阅读(303)  评论(0编辑  收藏  举报