B树——思路、及C语言代码的实现

0.序

  本人现读本科大二,这学期学习数据结构,老师为我们的期末作业布置一道任选题,而我一直以来都有听说B树是一棵挺神奇的树,所以我选择了它,当然更重要的原因是因为B树的难度最高,我喜欢做有挑战性的工作。同时,我听我基友说他热衷于将自己所学所想分享到博客园上,故才有了这样一篇文章。希望我能够在写博客的同时学习到更多东西,同时也能帮助到其他遇到或者即将遇到雷同问题的初学者们。

1.关于B树

  B树是一种称之为查找树的树,与之类似的有查找二叉树,平衡二叉树,除此之外,还有各种B树的兄弟姐妹B+树、B-树、B*树等,他们共同的特点就是都是按照一定的顺序规律存储的。B树的应用也是很广泛的,B树是几乎所有数据库的默认索引结构,也是用的最多的索引结构。B树是一种多叉树,根据其最多叉的数目可以直接称为M阶B树。根据算法导论上叙述,还可按B树每个节点最少的分支确定一棵B树的阶,但是这样的话B树的阶便必须为偶数。我个人是使用根据最大分支的数目确定B树的阶的。

  下图就是某一棵B树,每一个结点中都包含有数个数据元素,而同时一定会有数据元素的个数加一个的子树。

  一棵M阶B树或为空树,或为满足下列特性的M叉树:

(1)树中每个结点最多含有M棵子树;

(2)若根结点不是叶子结点,则至少有2棵子树;

(3)除根结点之外的所有非终端结点至少有[m/2]棵子树;

(4)每个非终端结点中包含的信息keynum,ptr[0],key[1],ptr[1],key[2],ptr[2],……key[keynum],ptr[keynum];

  其中,key为关键字,且关键字按升序排序,ptr为指向子树的根结点指针

2.思路及实现

  B树的接口主要是插入(包括空树插入一个元素)和删除操作,而插入和删除操作不可避免的都会用到查找操作,而查找的主要思路比较简单,主要是利用B树是一种排序树的原理,可以很快找到要插入位置或者要删除结点。这里的关键是注意返回内容包括查找结果所在结点,以及该元素所在位置,这是为了方便接下来的操作比较简单。

插入:

  通过对B树进行遍历,找出要插入的结点以及结点位置,如果找到的key值在B树当中已经存在,则说明插入失败,否则,就可以进行插入操作。这里可以先不管是否超出M阶树的上限要求,因为我们在定义的时候会故意留下一个位置,可以存放多余的一个元素,插入之后,通过判断是否达到M阶树上限要求,再进行递归的分裂操作。

 

 1 /***
 2 *  @name           Status insertBTree(BTree &T, Record e)
 3 *  @description    插入实现元素的插入
 4 *  @return         成功返回OK,如果存在则返回FALSE,否则返回ERROR
 5 *  @notice
 6 ***/
 7 Status insertBTree(BTree &T, Record e)
 8 {
 9     BTree p;
10     int index, temp;
11     Status find_flag;
12     if (NULL == T)//考虑B树为空树的情况
13     {
14         T = (BTree)malloc(BTLEN);
15         if (NULL == T) return OVERFLOW;
16         T->keynum = 1;
17         T->parent = NULL;
18         for (index = 0;index <= m; ++index)
19         {
20             T->ptr[index] = NULL;
21             T->key[index] = 0;
22         }
23         T->key[1] = e.key;
24         return OK;
25     }
26     find_flag = findBTree(T, p, temp, e.key);//寻找插入节点
27     if (find_flag == TRUE)
28     {
29         return FALSE;
30     }
31     if (find_flag == FALSE)
32     {                                //不管怎样先直接插入
33         p->keynum++;
34         for (index = p->keynum;index > temp;--index)
35         {
36             p->key[index] = p->key[index - 1];
37             p->ptr[index] = p->ptr[index - 1];
38         }
39         p->ptr[temp] = NULL;
40         p->key[temp] = e.key;
41         if (p->keynum == m)      //这种情况得分裂
42         {
43             splitBTree(p);
44         }
45         renewParent(T);
46         return OK;
47     }
48     return ERROR;
49 }

 

 

 

分裂:

  分裂操作是插入操作过程中一个最重要的操作,因为这是处理“冲突”(即结点中的数据元素大于B树规则中要求的最大个数)的一个通用的处理方式,这种方式必须要对所有的情况都适用,而分裂是解决这一问题一个方法。当然这种方法只是考虑到效率,没有对兄弟可否借数据进行判断,但是另外一种方式比较麻烦,这里先不做讨论。

  分裂的思路是让父亲结点先腾出一个位置(包括key和ptr)出来,然后在需要分裂的结点里面取中间的元素并且移动中间的元素key到父亲结点已经腾出来的key位置那里,然后把分裂出来的右部分接到腾出来的ptr那里。注意整个过程对左部分和右部分的都要改变元素的个数以及清空一些没用的空间。在往上分裂之后可能会造成一种情况,就是父亲结点也可能达到分裂的最大个数,所以,检查父亲结点是否需要分裂,需要的话,递归之。

 

 1 /***
 2 *  @name           status splitBTree(BTree T)
 3 *  @description    递归实现分裂节点操作
 4 *  @return         成功返回OK,否则返回ERROR
 5 *  @notice
 6 ***/
 7 Status splitBTree(BTree T) //此时分裂的节点一定会是超出最大值的。
 8 {
 9     BTree t1, t2;
10     int index, index_1;
11     if (T->parent == NULL)
12     {
13         t1 = (BTree)malloc(BTLEN);
14         if (NULL == t1) return OVERFLOW;
15         t2 = (BTree)malloc(BTLEN);
16         if (NULL == t2) return OVERFLOW;
17 
18         t1->keynum = m / 2;
19         t2->keynum = m - (m / 2) - 1;
20         t1->parent = T;
21         t2->parent = T;
22         for (index = 0;index <= m; ++index)  //先全部初始化
23         {
24             t1->ptr[index] = NULL;
25             t1->key[index] = 0;
26             t2->ptr[index] = NULL;
27             t2->key[index] = 0;
28         }
29         for (index = 0;index <= m / 2; ++index)  //初始化t1
30         {
31             t1->ptr[index] = T->ptr[index];
32             t1->key[index] = T->key[index];
33         }
34         t2->ptr[0] = T->ptr[(m / 2) + 1];
35         for (index = (m / 2) + 2;index <= m; ++index)  //初始化t2
36         {
37             t2->ptr[index - ((m / 2) + 1)] = T->ptr[index];
38             t2->key[index - ((m / 2) + 1)] = T->key[index];
39         }
40         T->keynum = 1;
41         T->ptr[0] = t1;
42         T->ptr[1] = t2;
43         T->key[1] = T->key[m / 2 + 1];
44         for (index = 2;index <= m; ++index)  //初始化T
45         {
46             T->ptr[index] = NULL;
47             T->key[index] = 0;
48         }
49         return OK;
50     }

 

删除:

  B树元素的删除操作与插入操作类似,但是却要麻烦,因为得分两种情况处理。(1)寻找到存在这个元素,而且这个元素所在是叶子节点(即它的孩子为空),直接对其进行删除,之后再判断是否小于B树规则中要求的最小的子树个数。如果小于,那就调用合并函数。(2)如果寻找到的这个元素是非叶子节点的元素,通过寻找比该元素小的最大元素(该元素肯定为叶子节点),把该元素直接赋值给要删除的元素,再在叶子节点处进行(1)中的操作。

 1 /***
 2 *  @name           Status deleteBTreeRecord(BTree &T, Record e)
 3 *  @description    实现B树元素的删除
 4 *  @return         成功返回OK,否则返回ERROR
 5 *  @notice
 6 ***/
 7 Status deleteBTreeRecord(BTree &T, Record e)
 8 {
 9     BTree p, q;
10     int num, temp, index;
11     Status find_flag;
12     if (T == NULL)
13         return ERROR;
14     find_flag = findBTree(T, p, temp, e.key);
15     if (find_flag == FALSE)
16     {
17         return FALSE;
18     }
19     if (find_flag == TRUE)
20     {
21         //deleteBTreeBNode(p,temp);
22         if (p->ptr[temp] == NULL)                //如果是叶子节点的话
23         {
24             for (index = temp;index <= p->keynum;++index)
25             {
26                 p->key[index] = p->key[index + 1];
27                 p->ptr[index] = p->ptr[index + 1];
28             }
29             p->keynum--;
30             if (p->keynum == (m + 1) / 2 - 2)
31             {
32                 //调用借兄弟的函数
33                 if (borrowBNode(p) == EMPTY) T = NULL;
34                 else renewParent(T);
35             }
36             return OK;
37         }
38         else                                    //不是叶子结点的话
39         {
40             //遍历
41             findMax(p->ptr[temp - 1], q, num);//返回的q一定会是叶子节点
42             p->key[temp] = q->key[num];
43             q->key[num] = 0;
44             q->keynum--;
45             if (q->keynum == (m + 1) / 2 - 2)
46             {
47                 //调用借兄弟的函数
48                 if (borrowBNode(q) == EMPTY) T = NULL;
49                 else renewParent(T);
50             }
51             return OK;
52         }
53         return OK;
54     }
55     return ERROR;
56 }

 

合并:

  在此先声明,因为一开始只考虑B树的阶为4的情况,后来改为使用宏定义阶M的数值,所以这段代码存在BUG,只支持阶为3或4的B树= =。

  思路还是挺清晰的,首先先向兄弟结点借元素,如果兄弟能够借给你元素的话(即借了你之后并不会小于最少的分支),那么直接从兄弟那里取元素,否则,和兄弟合并。

  合并其实是分裂反过来的情况,从父亲结点那里取出一个key值介于要合并的两个结点之间的元素,插入左部分最末尾处,同时右部分插到左部分后面,然后父亲结点元素依次往前挪。从而实现合并操作。之后,也必须对父亲结点进行判断是否小于最小的分支数,如果也小于,对父亲节点进行递归操作。

  1 /***
  2 *  @name           Status borrowBNode(BTree &T)
  3 *  @description    递归实现,向兄弟借元素,否则和兄弟合并
  4 *  @return         成功返回OK,否则返回ERROR
  5 *  @notice         这种情况应该是T为单元素结点
  6 ***/
  7 Status borrowBNode(BTree T)
  8 {
  9     int mynum, bronum, index;
 10     BTree b = NULL, f = NULL;
 11     if (T == NULL) return ERROR;
 12     f = T->parent;
 13     if (f == NULL)//考虑父亲结点不存在的情况
 14     {
 15         if (T->keynum == 0)
 16         {
 17             f = T->ptr[0];
 18             if (f == NULL)
 19             {
 20                 free(T);
 21                 return EMPTY;
 22             }
 23             for (index = 0;index <= f->keynum;index++)
 24             {
 25                 T->key[index] = f->key[index];
 26                 T->ptr[index] = f->ptr[index];
 27             }
 28             T->keynum = f->keynum;
 29             free(f);
 30             renewParent(T);
 31         }
 32         return OK;
 33     }
 34     mynum = whichSon(T);
 35     if (mynum == 0)
 36         bronum = 1;
 37     else
 38         bronum = mynum - 1;
 39     b = f->ptr[bronum];
 40     if (b->keynum == (m + 1) / 2 - 1) //如果兄弟帮不了你了
 41     {
 42         //那么就和这个兄弟合体
 43         if (bronum < mynum)                    //如果我不是第一个
 44         {
 45             b->keynum++;
 46             b->key[b->keynum] = f->key[mynum];
 47             b->ptr[b->keynum] = T->ptr[0];
 48             for (index = 1;index <= T->keynum;index++)
 49             {
 50                 b->key[index + b->keynum] = T->key[index];
 51                 b->ptr[index + b->keynum] = T->ptr[index];
 52                 b->keynum++;
 53             }
 54             free(T);
 55             for (index = mynum;index <= f->keynum;index++)
 56             {
 57                 f->key[index] = f->key[index + 1];
 58                 f->ptr[index] = f->ptr[index + 1];
 59             }
 60             f->keynum--;
 61         }
 62         else
 63         {
 64             T->keynum++;
 65             T->key[T->keynum] = f->key[bronum];
 66             T->ptr[T->keynum] = b->ptr[0];
 67             for (index = 1;index <= b->keynum;index++)
 68             {
 69                 T->key[index + T->keynum] = b->key[index];
 70                 T->ptr[index + T->keynum] = b->ptr[index];
 71                 T->keynum++;
 72             }
 73             free(b);
 74             for (index = bronum;index <= f->keynum;index++)
 75             {
 76                 f->key[index] = f->key[index + 1];
 77                 f->ptr[index] = f->ptr[index + 1];
 78             }
 79             f->keynum--;
 80         }
 81         renewParent(f);
 82         if (f->keynum == (m + 1) / 2 - 2)
 83         {
 84             //调用借兄弟的函数
 85             return borrowBNode(f);
 86         }
 87     }
 88     else//如果兄弟能够帮你
 89     {
 90         if (bronum < mynum)                    //如果我不是第一个
 91         {
 92             for (index = 1;index <= T->keynum;index++)
 93             {
 94                 T->key[index + 1] = T->key[index];
 95                 T->ptr[index + 1] = T->ptr[index];
 96             }
 97             T->ptr[1] = T->ptr[0];
 98             T->key[1] = f->key[mynum];
 99             T->ptr[0] = b->ptr[b->keynum];
100             T->keynum++;
101             f->key[mynum] = b->key[b->keynum];
102             b->key[b->keynum] = 0;
103             b->ptr[b->keynum] = NULL;
104             b->keynum--;
105 
106         }
107         else                                    //如果我是第一个
108         {
109             T->keynum++;
110             T->key[T->keynum] = f->key[1];
111             T->ptr[T->keynum] = b->ptr[0];
112             f->key[1] = b->key[1];
113             b->ptr[0] = b->ptr[1];
114             for (index = 1;index <= b->keynum;index++)
115             {
116                 b->key[index] = b->key[index + 1];
117                 b->ptr[index] = b->ptr[index + 1];
118             }
119             b->keynum--;
120         }
121     }
122     return OK;
123 }

遍历,输出:

  为了让B树更容易看,代码更容易调试,我同时还用队列写了个层次遍历,这个看看就好,实现起来挺麻烦的。而且可能代码实现也存在问题

 1 /***
 2 *  @name           Status ergodic(BTree T, LinkList L, int newline, int sum)
 3 *  @description    print需要用到的递归遍历程序
 4 *  @return         成功返回OK
 5 *  @notice         此处用到队列
 6 ***/
 7 Status ergodic(BTree T, LinkList L, int newline, int sum)
 8 {
 9     int index;
10     BTree p;
11     if (T != NULL)
12     {
13         printf("[ ");
14         Enqueue_L(L, T->ptr[0]);
15         for (index = 1;index <= T->keynum; index++)
16         {
17             printf("%d ", T->key[index]);
18             Enqueue_L(L, T->ptr[index]);
19         }
20         sum += T->keynum + 1;
21         printf("]");
22         if (newline == 0)
23         {
24             printf("\n");
25             newline = sum - 1;
26             sum = 0;
27         }
28         else
29         {
30             --newline;
31         }
32     }
33     if (IfEmpty(L) == FALSE)
34     {
35         Dequeue_L(L, p);
36         ergodic(p, L, newline, sum);
37     }
38     return OK;
39 }
40 /***
41 *  @name           Status print(BTree T)
42 *  @description    层次遍历并分层输出B树
43 *  @return         成功返回OK
44 *  @notice
45 ***/
46 Status print(BTree T)
47 {
48     LinkList L;
49     if (T == NULL)
50     {
51         printf("[ ]\n");
52         return OK;
53     }
54     InitQueue_L(L);
55     ergodic(T, L, 0, 0);
56     DestroyQueue(L);
57     return OK;
58 }

 

3.测试

 

4.总结

  以目前所掌握的知识,终于把B树做出来了,整个过程没有参考过其他人的代码,所以并不知道自己的一些思路是否得当,如有错误,多多包涵。在整个过程中,最难,卡的最久的也就是合并操作了,这块的代码也是乱得掉渣,以后有时间把他完善了。最后附上完整代码。

  1 #define _CRT_SECURE_NO_WARNINGS
  2 #include<stdio.h>         
  3 #include<stdlib.h>
  4 #include<time.h>  
  5 #define BTREELENGTH 50
  6 #define BTLEN (sizeof(BTNode))
  7 #define MAXINT 100  
  8 typedef enum status
  9 {
 10     TRUE,
 11     FALSE,
 12     OK,
 13     ERROR,
 14     OVERFLOW,
 15     EMPTY
 16 }Status;
 17 typedef int KeyType;
 18 
 19 //**********************************B树****************************************
 20 #define  m  3   // B树的阶,此设为4
 21 typedef struct 
 22 {
 23     KeyType  key;
 24     char     data;
 25 } Record;
 26 typedef struct BTNode 
 27 {
 28     int             keynum;        // 结点中关键字个数,即结点的大小
 29     struct BTNode  *parent;        // 指向双亲结点
 30     KeyType         key[m + 1];      // 关键字向量,0号单元未用
 31     struct BTNode  *ptr[m + 1];      // 子树指针向量
 32 //  Record         *recptr[m + 1];   // 记录指针向量,0号单元未用
 33                                      //在此添加其他自定义数据
 34 } BTNode, *BTree;                // B树结点和B树的类型
 35 typedef struct 
 36 {
 37     BTNode  *pt;      // 指向找到的结点
 38     int      i;       // 1..m,在结点中的关键字序号
 39     int      tag;     // 1:查找成功,0:查找失败
 40 } Result;           // 在B树的查找结果类型   
 41 //**********************************B树****************************************
 42 
 43 //**********************************队列***************************************
 44 typedef struct LNode {
 45     BTree data;     // 数据域
 46     struct LNode *next;     // 指针域
 47 } LNode, *LinkList;
 48 //**********************************队列***************************************
 49 
 50 /***
 51 *  @name           Status InitQueue_L(LinkList &L)
 52 *  @description    初始化队列
 53 *  @return         成功返回OK,开辟空间失败返回OVERFLOW
 54 *  @notice
 55 ***/
 56 Status InitQueue_L(LinkList &L)
 57 { // 初始化一个只含头结点的空单链表L
 58     if (NULL == (L = (LNode*)malloc(sizeof(LNode)))) // 生成新结点
 59         return OVERFLOW;
 60     L->next = NULL;
 61     return OK;
 62 }
 63 /***
 64 *  @name           LNode* MakeNode_L(BTree e)
 65 *  @description    构造队列结点
 66 *  @return         返回结点地址
 67 *  @notice
 68 ***/
 69 LNode* MakeNode_L(BTree e)
 70 { // 构造数据域为e的单链表结点
 71     LNode *p;
 72     p = (LNode*)malloc(sizeof(LNode)); // 分配结点空间
 73     if (p != NULL)
 74     {
 75         p->data = e;
 76         p->next = NULL;
 77     }
 78     return p;
 79 }
 80 /***
 81 *  @name           Status Enqueue_L(LNode *p, BTree e)
 82 *  @description    队列的入队
 83 *  @return         成功返回OK,否则返回ERROR
 84 *  @notice
 85 ***/
 86 Status Enqueue_L(LNode *p, BTree e)
 87 { //在p结点之后插入q结点
 88     if (NULL == p) return ERROR; // 参数不合理
 89     while (p->next != NULL)
 90         p = p->next;
 91     p->next = MakeNode_L(e);         // 对应图4.11(b)的②,修改p结点的指针域
 92     return OK;
 93 }
 94 
 95 /***
 96 *  @name           Status Dequeue_L(LNode *p, BTree &e)
 97 *  @description    队列的出队
 98 *  @return         成功返回OK,否则返回ERROR
 99 *  @notice
100 ***/
101 Status Dequeue_L(LNode *p, BTree &e)
102 {
103     // 删除p结点的直接后继结点并用参数e返回被删结点的值
104     LNode *q;
105     if (NULL == p || NULL == p->next) return ERROR; // 删除位置不合理 
106     q = p->next;
107     p->next = q->next; // 修改被删结点q的指针域
108     e = q->data;
109     free(q); // 释放结点q
110     return OK;
111 }
112 
113 /***
114 *  @name           void DestroyQueue(LinkList L)
115 *  @description    队列的销毁
116 *  @return         无返回
117 *  @notice
118 ***/
119 void DestroyQueue(LinkList L)
120 {
121     // 销毁整个链表
122     LinkList p;
123     if (L != NULL)
124     {
125         p = L;
126         L = L->next;
127         free(p);
128         DestroyQueue(L);
129     }
130 }
131 /***
132 *  @name           Status  IfEmpty(LinkList L)
133 *  @description    判断队列是否为空
134 *  @return         空返回TRUE,不空返回FALSE,否则返回ERROR
135 *  @notice         
136 ***/
137 Status  IfEmpty(LinkList L)
138 {
139     if (L == NULL) return ERROR;
140     if (L->next == NULL) return TRUE;
141     return FALSE;
142 }
143 /***
144 *  @name           Status ergodic(BTree T, LinkList L, int newline, int sum)
145 *  @description    print需要用到的递归遍历程序
146 *  @return         成功返回OK
147 *  @notice         此处用到队列
148 ***/
149 Status ergodic(BTree T, LinkList L, int newline, int sum)
150 {
151     int index;
152     BTree p;
153     if (T != NULL)
154     {
155         printf("[ ");
156         Enqueue_L(L, T->ptr[0]);
157         for (index = 1;index <= T->keynum; index++)
158         {
159             printf("%d ", T->key[index]);
160             Enqueue_L(L, T->ptr[index]);
161         }
162         sum += T->keynum + 1;
163         printf("]");
164         if (newline == 0)
165         {
166             printf("\n");
167             newline = sum - 1;
168             sum = 0;
169         }
170         else
171         {
172             --newline;
173         }
174     }
175     if (IfEmpty(L) == FALSE)
176     {
177         Dequeue_L(L, p);
178         ergodic(p, L, newline, sum);
179     }
180     return OK;
181 }
182 /***
183 *  @name           Status print(BTree T)
184 *  @description    层次遍历并分层输出B树
185 *  @return         成功返回OK
186 *  @notice
187 ***/
188 Status print(BTree T)
189 {
190     LinkList L;
191     if (T == NULL)
192     {
193         printf("[ ]\n");
194         return OK;
195     }
196     InitQueue_L(L);
197     ergodic(T, L, 0, 0);
198     DestroyQueue(L);
199     return OK;
200 }
201 
202 /***
203 *  @name           Status findMax(BTree T, BTree &p,int ans)
204 *  @description    寻找最大关键字的结点,T为要寻找的树,p为返回的节点,ans为第几个
205 *  @return         成功返回OK,否则返回ERROR
206 *  @notice
207 ***/
208 Status findMax(BTree T, BTree &p, int &ans)
209 {
210     if (T == NULL)
211         return ERROR;
212     p = T;
213     while (p->ptr[p->keynum] != NULL)
214     {
215         p = p->ptr[p->keynum];
216     }
217     ans = p->keynum;
218     return OK;
219 }
220 /***
221 *  @name           Status findMin(BTree T, BTree &p,int ans)
222 *  @description    寻找最小关键字的结点,T为要寻找的树,p为返回的节点,ans为第几个
223 *  @return         成功返回OK,否则返回ERROR
224 *  @notice
225 ***/
226 /***
227 *  @name           Status findBTree(BTree T, BTree &p, int &ans, KeyType k)
228 *  @description    寻找 ,T为要寻找的树,p为返回的节点,ans为第几个元素,k为要找的值
229 *  @return         成功返回OK,否则返回ERROR
230 *  @notice
231 ***/
232 Status findBTree(BTree T, BTree &p, int &ans, KeyType k)
233 {
234     BTree q;
235     int index = 1;
236     KeyType  keynow;
237     if (T == NULL)
238         return ERROR;
239     q = T;
240     keynow = T->key[1];
241     while (q != NULL)                 //深度的遍历
242     {
243         index = 1;
244         keynow = q->key[index];
245         while (index <= q->keynum) //节点内对各真值进行遍历
246         {
247             if (k == keynow)           //找到元素
248             {
249                 p = q;
250                 ans = index;
251                 return TRUE;
252             }
253             if (k > keynow)
254             {
255                 if (index == q->keynum)
256                 {
257                     if (q->ptr[index] == NULL)
258                     {
259                         p = q;
260                         ans = q->keynum + 1;
261                         return FALSE;
262                     }
263                     q = q->ptr[index];
264                     break;
265                 }
266                 ++index;
267                 keynow = q->key[index];
268                 continue;
269             }
270             if (k < keynow)
271             {
272                 if (q->ptr[index - 1] == NULL)
273                 {
274                     p = q;
275                     ans = index;
276                     return FALSE;
277                 }
278                 q = q->ptr[index - 1];
279                 break;
280             }
281         }
282     }
283 
284     return ERROR;
285 }
286 /***
287 *  @name           Status renewParent(BTree p)
288 *  @description    告诉孩子们亲身爸爸是谁
289 *  @return         成功返回OK,否则返回ERROR
290 *  @notice
291 ***/
292 Status renewParent(BTree p)
293 {
294     int index;
295     if (p == NULL) return ERROR;
296     for (index = 0;index <= p->keynum;++index)
297     {
298         if (p->ptr[index] != NULL)
299         {
300             p->ptr[index]->parent = p;
301             renewParent(p->ptr[index]);
302         }
303     }
304     return OK;
305 }
306 /***
307 *  @name           int whichSon(BTree T)
308 *  @description    找出是父亲的第几个孩子
309 *  @return         成功返回第几个孩子,否则返回-1
310 *  @notice
311 ***/
312 int whichSon(BTree T)
313 {
314     int index = -1;
315     if (T == NULL) return -1;
316     for (index = 0;index <= T->parent->keynum;++index) //找出是父亲的第几个孩子
317     {
318         if (T->parent->ptr[index] == T) return index;
319     }
320     return -1;
321 }
322 /***
323 *  @name           status splitBTree(BTree T)
324 *  @description    递归实现分裂节点操作
325 *  @return         成功返回OK,否则返回ERROR
326 *  @notice
327 ***/
328 Status splitBTree(BTree T) //此时分裂的节点一定会是超出最大值的。
329 {
330     BTree t1, t2;
331     int index, index_1;
332     if (T->parent == NULL)
333     {
334         t1 = (BTree)malloc(BTLEN);
335         if (NULL == t1) return OVERFLOW;
336         t2 = (BTree)malloc(BTLEN);
337         if (NULL == t2) return OVERFLOW;
338 
339         t1->keynum = m / 2;
340         t2->keynum = m - (m / 2) - 1;
341         t1->parent = T;
342         t2->parent = T;
343         for (index = 0;index <= m; ++index)  //先全部初始化
344         {
345             t1->ptr[index] = NULL;
346             t1->key[index] = 0;
347             t2->ptr[index] = NULL;
348             t2->key[index] = 0;
349         }
350         for (index = 0;index <= m / 2; ++index)  //初始化t1
351         {
352             t1->ptr[index] = T->ptr[index];
353             t1->key[index] = T->key[index];
354         }
355         t2->ptr[0] = T->ptr[(m / 2) + 1];
356         for (index = (m / 2) + 2;index <= m; ++index)  //初始化t2
357         {
358             t2->ptr[index - ((m / 2) + 1)] = T->ptr[index];
359             t2->key[index - ((m / 2) + 1)] = T->key[index];
360         }
361         T->keynum = 1;
362         T->ptr[0] = t1;
363         T->ptr[1] = t2;
364         T->key[1] = T->key[m / 2 + 1];
365         for (index = 2;index <= m; ++index)  //初始化T
366         {
367             T->ptr[index] = NULL;
368             T->key[index] = 0;
369         }
370         return OK;
371     }
372 
373     index = whichSon(T);
374     for (index_1 = T->parent->keynum;index_1 > index;--index_1) //腾出父亲的位置
375     {
376         T->parent->ptr[index_1 + 1] = T->parent->ptr[index_1];
377         T->parent->key[index_1 + 1] = T->parent->key[index_1];
378     }
379     T->parent->keynum++;
380     T->parent->key[index + 1] = T->key[m / 2 + 1];
381     t2 = T->parent->ptr[index + 1] = (BTree)malloc(BTLEN);
382     if (NULL == t2) return OVERFLOW;
383     for (index = 0;index <= m; ++index)  //先全部初始化
384     {
385         t2->ptr[index] = NULL;
386         t2->key[index] = 0;
387     }
388     t2->keynum = m - (m / 2) - 1;
389     t2->parent = T->parent;
390     t2->ptr[0] = T->ptr[(m / 2) + 1];
391     for (index = (m / 2) + 2;index <= m; ++index)  //初始化t2
392     {
393         t2->ptr[index - ((m / 2) + 1)] = T->ptr[index];
394         t2->key[index - ((m / 2) + 1)] = T->key[index];
395     }
396     T->keynum = m / 2;
397     for (index = (m / 2) + 1;index <= m; ++index)  //初始化t2
398     {
399         T->ptr[index] = NULL;
400         T->key[index] = 0;
401     }
402     if (T->parent->keynum == m)
403     {
404         splitBTree(T->parent);
405     }
406     return OK;
407 }
408 /***
409 *  @name           Status insertBTree(BTree &T, Record e)
410 *  @description    插入实现元素的插入
411 *  @return         成功返回OK,如果存在则返回FALSE,否则返回ERROR
412 *  @notice
413 ***/
414 Status insertBTree(BTree &T, Record e)
415 {
416     BTree p;
417     int index, temp;
418     Status find_flag;
419     if (NULL == T)
420     {
421         T = (BTree)malloc(BTLEN);
422         if (NULL == T) return OVERFLOW;
423         T->keynum = 1;
424         T->parent = NULL;
425         for (index = 0;index <= m; ++index)
426         {
427             T->ptr[index] = NULL;
428             T->key[index] = 0;
429         }
430         T->key[1] = e.key;
431         return OK;
432     }
433     find_flag = findBTree(T, p, temp, e.key);
434     if (find_flag == TRUE)
435     {
436         return FALSE;
437     }
438     if (find_flag == FALSE)
439     {                                //不管怎样先直接插入
440         p->keynum++;
441         for (index = p->keynum;index > temp;--index)
442         {
443             p->key[index] = p->key[index - 1];
444             p->ptr[index] = p->ptr[index - 1];
445         }
446         p->ptr[temp] = NULL;
447         p->key[temp] = e.key;
448         if (p->keynum == m)      //这种情况得分裂
449         {
450             splitBTree(p);
451         }
452         renewParent(T);
453         return OK;
454     }
455     return ERROR;
456 }
457 /***
458 *  @name           Status borrowBNode(BTree &T)
459 *  @description    递归实现,向兄弟借元素,否则和兄弟合并
460 *  @return         成功返回OK,否则返回ERROR
461 *  @notice         这种情况应该是T为单元素结点
462 ***/
463 Status borrowBNode(BTree T)
464 {
465     int mynum, bronum, index;
466     BTree b = NULL, f = NULL;
467     if (T == NULL) return ERROR;
468     f = T->parent;
469     if (f == NULL)//考虑父亲结点不存在的情况
470     {
471         if (T->keynum == 0)
472         {
473             f = T->ptr[0];
474             if (f == NULL)
475             {
476                 free(T);
477                 return EMPTY;
478             }
479             for (index = 0;index <= f->keynum;index++)
480             {
481                 T->key[index] = f->key[index];
482                 T->ptr[index] = f->ptr[index];
483             }
484             T->keynum = f->keynum;
485             free(f);
486             renewParent(T);
487         }
488         return OK;
489     }
490     mynum = whichSon(T);
491     if (mynum == 0)
492         bronum = 1;
493     else
494         bronum = mynum - 1;
495     b = f->ptr[bronum];
496     if (b->keynum == (m + 1) / 2 - 1) //如果兄弟帮不了你了
497     {
498         //那么就和这个兄弟合体
499         if (bronum < mynum)                    //如果我不是第一个
500         {
501             b->keynum++;
502             b->key[b->keynum] = f->key[mynum];
503             b->ptr[b->keynum] = T->ptr[0];
504             for (index = 1;index <= T->keynum;index++)
505             {
506                 b->key[index + b->keynum] = T->key[index];
507                 b->ptr[index + b->keynum] = T->ptr[index];
508                 b->keynum++;
509             }
510             free(T);
511             for (index = mynum;index <= f->keynum;index++)
512             {
513                 f->key[index] = f->key[index + 1];
514                 f->ptr[index] = f->ptr[index + 1];
515             }
516             f->keynum--;
517         }
518         else
519         {
520             T->keynum++;
521             T->key[T->keynum] = f->key[bronum];
522             T->ptr[T->keynum] = b->ptr[0];
523             for (index = 1;index <= b->keynum;index++)
524             {
525                 T->key[index + T->keynum] = b->key[index];
526                 T->ptr[index + T->keynum] = b->ptr[index];
527                 T->keynum++;
528             }
529             free(b);
530             for (index = bronum;index <= f->keynum;index++)
531             {
532                 f->key[index] = f->key[index + 1];
533                 f->ptr[index] = f->ptr[index + 1];
534             }
535             f->keynum--;
536         }
537         renewParent(f);
538         if (f->keynum == (m + 1) / 2 - 2)
539         {
540             //调用借兄弟的函数
541             return borrowBNode(f);
542         }
543     }
544     else//如果兄弟能够帮你
545     {
546         if (bronum < mynum)                    //如果我不是第一个
547         {
548             for (index = 1;index <= T->keynum;index++)
549             {
550                 T->key[index + 1] = T->key[index];
551                 T->ptr[index + 1] = T->ptr[index];
552             }
553             T->ptr[1] = T->ptr[0];
554             T->key[1] = f->key[mynum];
555             T->ptr[0] = b->ptr[b->keynum];
556             T->keynum++;
557             f->key[mynum] = b->key[b->keynum];
558             b->key[b->keynum] = 0;
559             b->ptr[b->keynum] = NULL;
560             b->keynum--;
561 
562         }
563         else                                    //如果我是第一个
564         {
565             T->keynum++;
566             T->key[T->keynum] = f->key[1];
567             T->ptr[T->keynum] = b->ptr[0];
568             f->key[1] = b->key[1];
569             b->ptr[0] = b->ptr[1];
570             for (index = 1;index <= b->keynum;index++)
571             {
572                 b->key[index] = b->key[index + 1];
573                 b->ptr[index] = b->ptr[index + 1];
574             }
575             b->keynum--;
576         }
577     }
578     return OK;
579 }
580 
581 /***
582 *  @name           Status deleteBTreeRecord(BTree &T, Record e)
583 *  @description    实现B树元素的删除
584 *  @return         成功返回OK,否则返回ERROR
585 *  @notice
586 ***/
587 Status deleteBTreeRecord(BTree &T, Record e)
588 {
589     BTree p, q;
590     int num, temp, index;
591     Status find_flag;
592     if (T == NULL)
593         return ERROR;
594     find_flag = findBTree(T, p, temp, e.key);
595     if (find_flag == FALSE)
596     {
597         return FALSE;
598     }
599     if (find_flag == TRUE)
600     {
601         //deleteBTreeBNode(p,temp);
602         if (p->ptr[temp] == NULL)                //如果是叶子节点的话
603         {
604             for (index = temp;index <= p->keynum;++index)
605             {
606                 p->key[index] = p->key[index + 1];
607                 p->ptr[index] = p->ptr[index + 1];
608             }
609             p->keynum--;
610             if (p->keynum == (m + 1) / 2 - 2)
611             {
612                 //调用借兄弟的函数
613                 if (borrowBNode(p) == EMPTY) T = NULL;
614                 else renewParent(T);
615             }
616             return OK;
617         }
618         else                                    //不是叶子结点的话
619         {
620             //遍历
621             findMax(p->ptr[temp - 1], q, num);//返回的q一定会是叶子节点
622             p->key[temp] = q->key[num];
623             q->key[num] = 0;
624             q->keynum--;
625             if (q->keynum == (m + 1) / 2 - 2)
626             {
627                 //调用借兄弟的函数
628                 if (borrowBNode(q) == EMPTY) T = NULL;
629                 else renewParent(T);
630             }
631             return OK;
632         }
633         return OK;
634     }
635     return ERROR;
636 }
637 /***
638 *  @name           Status initBTree(BTree &t)
639 *  @description    初始化一个空B树
640 *  @return         成功返回OK
641 *  @notice
642 ***/
643 Status initBTree(BTree &t)
644 {
645     t = NULL;
646     return OK;
647 }
648 /***
649 *  @name           Status test()
650 *  @description    针对数据结构实验做的测试函数
651 *  @return         成功返回OK
652 *  @notice
653 ***/
654 Status test()
655 {
656     // 测试代码
657     int n, i;
658     int arr[BTREELENGTH];
659     BTree a;
660     Record  d;
661     srand((unsigned)time(NULL));
662     n = rand() % BTREELENGTH;
663     //scanf("%d", &n);                    //可以改为自己输入数据
664     printf("B树的阶为:%d,插入次数为:%d\n", m, n);
665     initBTree(a);
666     for (i = 0;i < n;i++)
667     {
668         d.key = rand() % MAXINT;
669         //scanf("%d", &d.key);            //可以改为自己输入数据
670         arr[i] = d.key;
671         if (insertBTree(a, d) == OK)
672             printf("第%d次插入%d:\n", i + 1, d.key);
673         else
674             printf("第%d次插入%d不成功:\n", i + 1, d.key);
675         print(a);
676     }
677     for (i = 0;i < n;i++)
678     {
679         d.key = arr[i];
680         if (deleteBTreeRecord(a, d) == OK)
681             printf("第%d次删除%d:\n", i + 1, d.key);
682         else
683             printf("第%d次删除%d不成功:\n", i + 1, d.key);
684         print(a);
685     }
686     return OK;
687 
688 }
689 /***
690 主函数
691 ***/
692 int  main()
693 {
694     test();
695     return 0;
696 }
BTree

 

posted @ 2015-07-16 23:56  Hothoren  阅读(8950)  评论(3编辑  收藏  举报