B-Tree.h
1
//实现对order序(阶)的B-TREE结构基本操作的封装。 2 //查找:search,插入:insert,删除:remove。 3 //创建:create,销毁:destory,打印:print。 4 #ifndef BTREE_H 5 #define BTREE_H 6 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 11 ////* 定义m序(阶)B 树的最小度数BTree_D=ceil(m)*/ 12 /// 在这里定义每个节点中关键字的最大数目为:2 * BTree_D - 1,即序(阶):2 * BTree_D. 13 #define BTree_D 2 14 #define ORDER (BTree_D * 2) //定义为4阶B-tree,2-3-4树。最简单为3阶B-tree,2-3树。 15 //#define ORDER (BTree_T * 2-1) //最简单为3阶B-tree,2-3树。 16 17 typedef int KeyType; 18 typedef struct BTNode{ 19 int keynum; /// 结点中关键字的个数,keynum <= BTree_N 20 KeyType key[ORDER-1]; /// 关键字向量为key[0..keynum - 1] 21 struct BTNode* child[ORDER]; /// 孩子指针向量为child[0..keynum] 22 bool isLeaf; /// 是否是叶子节点的标志 23 }BTNode; 24 25 typedef BTNode* BTree; ///定义BTree 26 27 ///给定数据集data,创建BTree。 28 void BTree_create(BTree* tree, const KeyType* data, int length); 29 30 ///销毁BTree,释放内存空间。 31 void BTree_destroy(BTree* tree); 32 33 ///在BTree中插入关键字key。 34 void BTree_insert(BTree* tree, KeyType key); 35 36 ///在BTree中移除关键字key。 37 void BTree_remove(BTree* tree, KeyType key); 38 39 ///深度遍历BTree打印各层结点信息。 40 void BTree_print(const BTree tree, int layer=1); 41 42 /// 在BTree中查找关键字 key, 43 /// 成功时返回找到的节点的地址及 key 在其中的位置 *pos 44 /// 失败时返回 NULL 及查找失败时扫描到的节点位置 *pos 45 BTNode* BTree_search(const BTree tree, int key, int* pos); 46 47 #ifdef __cplusplus 48 } 49 #endif 50 51 #endif

B-Tree.c文件源码:

  1 //实现对order序(阶)的B-TREE结构基本操作的封装。 
  2 //查找:search,插入:insert,删除:remove。 
  3 //创建:create,销毁:destory,打印:print。 
  4 #include <stdlib.h> 
  5 #include <stdio.h> 
  6 #include <assert.h> 
  7 #include "btree.h" 
  8    
  9 //#define max(a, b) (((a) > (b)) ? (a) : (b)) 
 10 #define cmp(a, b) ( ( ((a)-(b)) >= (0) ) ? (1) : (0) ) //比较a,b大小 
 11 #define DEBUG_BTREE 
 12    
 13    
 14 // 模拟向磁盘写入节点 
 15 void disk_write(BTNode* node) 
 16 { 
 17 //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
 18     printf("向磁盘写入节点"); 
 19     for(int i=0;i<ORDER-1;i++){ 
 20         printf("%c",node->key[i]); 
 21     } 
 22     printf("\n"); 
 23 } 
 24    
 25 // 模拟从磁盘读取节点 
 26 void disk_read(BTNode** node) 
 27 { 
 28 //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
 29     printf("向磁盘读取节点"); 
 30     for(int i=0;i<ORDER-1;i++){ 
 31         printf("%c",(*node)->key[i]); 
 32     } 
 33     printf("\n"); 
 34 } 
 35    
 36 // 按层次打印 B 树 
 37 void BTree_print(const BTree tree, int layer) 
 38 { 
 39     int i; 
 40     BTNode* node = tree; 
 41    
 42     if (node) { 
 43         printf("第 %d 层, %d node : ", layer, node->keynum); 
 44    
 45         //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
 46         for (i = 0; i < ORDER-1; ++i) { 
 47         //for (i = 0; i < node->keynum; ++i) { 
 48             printf("%c ", node->key[i]); 
 49         } 
 50    
 51         printf("\n"); 
 52    
 53         ++layer; 
 54         for (i = 0 ; i <= node->keynum; i++) { 
 55             if (node->child[i]) { 
 56                 BTree_print(node->child[i], layer); 
 57             } 
 58         } 
 59     } 
 60     else { 
 61         printf("树为空。\n"); 
 62     } 
 63 } 
 64    
 65 // 结点node内对关键字进行二分查找。 
 66 int binarySearch(BTNode* node, int low, int high, KeyType Fkey) 
 67 { 
 68     int mid; 
 69     while (low<=high) 
 70     { 
 71         mid = low + (high-low)/2; 
 72         if (Fkey<node->key[mid]) 
 73         { 
 74             high = mid-1; 
 75         } 
 76         if (Fkey>node->key[mid]) 
 77         { 
 78             low = mid+1; 
 79         } 
 80         if (Fkey==node->key[mid]) 
 81         { 
 82             return mid;//返回下标。 
 83         } 
 84     } 
 85     return 0;//未找到返回0. 
 86 } 
 87    
 88  
 89 /***************************************************************************************
 90    将分裂的结点中的一半元素给新建的结点,并且将分裂结点中的中间关键字元素上移至父节点中。
 91    parent 是一个非满的父节点
 92    node 是 tree 孩子表中下标为 index 的孩子节点,且是满的,需分裂。
 93    分裂确保有序的情况下是均衡的
 94 *******************************************************************/ 
 95 void BTree_split_child(BTNode* parent, int index, BTNode* node) 
 96 { 
 97 #ifdef DEBUG_BTREE 
 98     printf("BTree_split_child!\n"); 
 99 #endif 
100     assert(parent && node); 
101     int i; 
102    
103     // 创建新节点,存储 node 中后半部分的数据 
104     BTNode* newNode = (BTNode*)calloc(sizeof(BTNode), 1); 
105     if (!newNode) { 
106         printf("Error! out of memory!\n"); 
107         return; 
108     } 
109    
110     newNode->isLeaf = node->isLeaf; 
111     newNode->keynum = BTree_D - 1; 
112    
113     // 拷贝 node 后半部分关键字,然后将node后半部分置为0。 
114     for (i = 0; i < newNode->keynum; ++i){ 
115         newNode->key[i] = node->key[BTree_D + i]; 
116         node->key[BTree_D + i] = 0; 
117     } 
118    
119     // 如果 node 不是叶子节点,拷贝 node 后半部分的指向孩子节点的指针,然后将node后半部分指向孩子节点的指针置为NULL。 
120     if (!node->isLeaf) { 
121         for (i = 0; i < BTree_D; i++) { 
122             newNode->child[i] = node->child[BTree_D + i]; 
123             node->child[BTree_D + i] = NULL; 
124         } 
125     } 
126    
127     // 将 node 分裂出 newNode 之后,里面的数据减半 
128     node->keynum = BTree_D - 1; 
129    
130     // 调整父节点中的指向孩子的指针和关键字元素。分裂时父节点增加指向孩子的指针和关键元素。 
131     for (i = parent->keynum; i > index; --i) { 
132         parent->child[i + 1] = parent->child[i]; 
133     } 
134    
135     parent->child[index + 1] = newNode; 
136    
137     for (i = parent->keynum - 1; i >= index; --i) { 
138         parent->key[i + 1] = parent->key[i]; 
139     } 
140    
141     parent->key[index] = node->key[BTree_D - 1]; 
142     ++parent->keynum; 
143    
144     node->key[BTree_D - 1] = 0; 
145    
146     // 写入磁盘 
147      disk_write(parent); 
148      disk_write(newNode); 
149      disk_write(node); 
150 } 
151    
152 void BTree_insert_nonfull(BTNode* node, KeyType key) 
153 { 
154     assert(node); 
155    
156     int i; 
157    
158     // 节点是叶子节点,直接插入,如果比其他值小,那么移动其他值 
159     if (node->isLeaf) { 
160         i = node->keynum - 1; 
161         while (i >= 0 && key < node->key[i]) { 
162             node->key[i + 1] = node->key[i]; 
163             --i; 
164         } 
165    
166         node->key[i + 1] = key; 
167         ++node->keynum; 
168    
169         // 写入磁盘 
170         disk_write(node); 
171     } 
172    
173     // 节点是内部节点 
174     else { 
175         /* 查找插入的位置*/ 
176         i = node->keynum - 1; 
177         while (i >= 0 && key < node->key[i]) { 
178             --i; 
179         } 
180    
181         ++i; 
182    
183         // 从磁盘读取孩子节点 
184         disk_read(&node->child[i]); 
185    
186         // 如果该孩子节点已满,分裂调整值 
187         if (node->child[i]->keynum == (ORDER-1)) { 
188             BTree_split_child(node, i, node->child[i]); 
189             // 如果待插入的关键字大于该分裂结点中上移到父节点的关键字,在该关键字的右孩子结点中进行插入操作。 
190             if (key > node->key[i]) { 
191                 ++i; 
192             } 
193         } 
194         BTree_insert_nonfull(node->child[i], key); 
195     } 
196 } 
197    
198 void BTree_insert(BTree* tree, KeyType key) 
199 { 
200 #ifdef DEBUG_BTREE 
201     printf("BTree_insert:\n"); 
202 #endif 
203     BTNode* node; 
204     BTNode* root = *tree; 
205    
206     // 树为空 
207     if (NULL == root) { 
208         root = (BTNode*)calloc(sizeof(BTNode), 1); 
209         if (!root) { 
210             printf("Error! out of memory!\n"); 
211             return; 
212         } 
213         root->isLeaf = true; 
214         root->keynum = 1; 
215         root->key[0] = key; 
216    
217         *tree = root; 
218    
219         // 写入磁盘 
220         disk_write(root); 
221    
222         return; 
223     } 
224    
225     // 根节点已满,插入前需要进行分裂调整 
226     if (root->keynum == (ORDER-1)) { 
227         // 产生新节点当作根 
228         node = (BTNode*)calloc(sizeof(BTNode), 1); 
229         if (!node) { 
230             printf("Error! out of memory!\n"); 
231             return; 
232         } 
233    
234         *tree = node; 
235         node->isLeaf = false; 
236         node->keynum = 0; 
237         node->child[0] = root; 
238    
239         BTree_split_child(node, 0, root); 
240    
241         BTree_insert_nonfull(node, key); 
242     } 
243    
244     // 根节点未满,在当前节点中插入 key 
245     else { 
246         BTree_insert_nonfull(root, key); 
247     } 
248 }
249 // 对 tree 中的节点 node 进行合并孩子节点处理. 
250 // 注意:孩子节点的 keynum 必须均已达到下限,即均等于 BTree_D - 1 
251 // 将 tree 中索引为 index 的 key 下移至左孩子结点中, 
252 // 将 node 中索引为 index + 1 的孩子节点合并到索引为 index 的孩子节点中,右孩子合并到左孩子结点中。 
253 // 并调相关的 key 和指针。
254 void BTree_merge_child(BTree* tree, BTNode* node, int index) 
255 {
256 #ifdef DEBUG_BTREE 
257     printf("BTree_merge_child!\n"); 
258 #endif 
259     assert(tree && node && index >= 0 && index < node->keynum); 
260    
261     int i; 
262    
263     KeyType key = node->key[index]; 
264     BTNode* leftChild = node->child[index]; 
265     BTNode* rightChild = node->child[index + 1]; 
266    
267     assert(leftChild && leftChild->keynum == BTree_D - 1 
268         && rightChild && rightChild->keynum == BTree_D - 1); 
269    
270     // 将 node中关键字下标为index 的 key 下移至左孩子结点中,该key所对应的右孩子结点指向node的右孩子结点中的第一个孩子。 
271     leftChild->key[leftChild->keynum] = key; 
272     leftChild->child[leftChild->keynum + 1] = rightChild->child[0]; 
273     ++leftChild->keynum; 
274    
275     // 右孩子的元素合并到左孩子结点中。 
276     for (i = 0; i < rightChild->keynum; ++i) { 
277         leftChild->key[leftChild->keynum] = rightChild->key[i]; 
278         leftChild->child[leftChild->keynum + 1] = rightChild->child[i + 1]; 
279         ++leftChild->keynum; 
280     } 
281    
282     // 在 node 中下移的 key后面的元素前移 
283     for (i = index; i < node->keynum - 1; ++i) { 
284         node->key[i] = node->key[i + 1]; 
285         node->child[i + 1] = node->child[i + 2]; 
286     } 
287     node->key[node->keynum - 1] = 0; 
288     node->child[node->keynum] = NULL; 
289     --node->keynum; 
290    
291     // 如果根节点没有 key 了,并将根节点调整为合并后的左孩子节点;然后删除释放空间。 
292     if (node->keynum == 0) { 
293         if (*tree == node) { 
294             *tree = leftChild; 
295         } 
296    
297         free(node); 
298         node = NULL; 
299     } 
300    
301     free(rightChild); 
302     rightChild = NULL; 
303 } 
304    
305 void BTree_recursive_remove(BTree* tree, KeyType key) 
306 { 
307     // B-数的保持条件之一: 
308     // 非根节点的内部节点的关键字数目不能少于 BTree_D - 1 
309    
310     int i, j, index; 
311     BTNode *root = *tree; 
312     BTNode *node = root; 
313    
314     if (!root) { 
315         printf("Failed to remove %c, it is not in the tree!\n", key); 
316         return; 
317     } 
318    
319     // 结点中找key。 
320     index = 0; 
321     while (index < node->keynum && key > node->key[index]) { 
322         ++index; 
323     } 
324    
325 /*======================含有key的当前结点时的情况====================
326 node:
327 index of Key:            i-1  i  i+1
328                         +---+---+---+---+
329                           *  key   *
330                     +---+---+---+---+---+
331                            /     \
332 index of Child:           i      i+1
333                          /         \
334                     +---+---+      +---+---+
335                       *   *           *   *   
336                 +---+---+---+  +---+---+---+
337                     leftChild     rightChild
338 ============================================================*/ 
339     /*一、结点中找到了关键字key的情况.*/ 
340     BTNode *leftChild, *rightChild; 
341     KeyType leftKey, rightKey; 
342     if (index < node->keynum && node->key[index] == key) { 
343         /* 1,所在节点是叶子节点,直接删除*/ 
344         if (node->isLeaf) { 
345             for (i = index; i < node->keynum-1; ++i) { 
346                 node->key[i] = node->key[i + 1]; 
347                 //node->child[i + 1] = node->child[i + 2];叶子节点的孩子结点为空,无需移动处理。 
348             } 
349             node->key[node->keynum-1] = 0; 
350             //node->child[node->keynum] = NULL; 
351             --node->keynum; 
352    
353             if (node->keynum == 0) { 
354                 assert(node == *tree); 
355                 free(node); 
356                 *tree = NULL; 
357             } 
358    
359             return; 
360         } 
361         /*2.选择脱贫致富的孩子结点。*/ 
362         // 2a,选择相对富有的左孩子结点。 
363         // 如果位于 key 前的左孩子结点的 key 数目 >= BTree_D, 
364         // 在其中找 key 的左孩子结点的最后一个元素上移至父节点key的位置。 
365         // 然后在左孩子节点中递归删除元素leftKey。 
366         else if (node->child[index]->keynum >= BTree_D) { 
367             leftChild = node->child[index]; 
368             leftKey = leftChild->key[leftChild->keynum - 1]; 
369             node->key[index] = leftKey; 
370    
371             BTree_recursive_remove(&leftChild, leftKey); 
372         } 
373         // 2b,选择相对富有的右孩子结点。 
374         // 如果位于 key 后的右孩子结点的 key 数目 >= BTree_D, 
375         // 在其中找 key 的右孩子结点的第一个元素上移至父节点key的位置 
376         // 然后在右孩子节点中递归删除元素rightKey。 
377         else if (node->child[index + 1]->keynum >= BTree_D) { 
378             rightChild = node->child[index + 1]; 
379             rightKey = rightChild->key[0]; 
380             node->key[index] = rightKey; 
381    
382             BTree_recursive_remove(&rightChild, rightKey); 
383         } 
384         /*左右孩子结点都刚脱贫。删除前需要孩子结点的合并操作*/ 
385         // 2c,左右孩子结点只包含 BTree_D - 1 个节点, 
386         // 合并是将 key 下移至左孩子节点,并将右孩子节点合并到左孩子节点中, 
387         // 删除右孩子节点,在父节点node中移除 key 和指向右孩子节点的指针, 
388         // 然后在合并了的左孩子节点中递归删除元素key。 
389         else if (node->child[index]->keynum == BTree_D - 1 
390             && node->child[index + 1]->keynum == BTree_D - 1){ 
391             leftChild = node->child[index]; 
392    
393             BTree_merge_child(tree, node, index); 
394    
395             // 在合并了的左孩子节点中递归删除 key 
396             BTree_recursive_remove(&leftChild, key); 
397         } 
398     } 
399    
400 /*======================未含有key的当前结点时的情况====================
401 node:
402 index of Key:            i-1  i  i+1
403                         +---+---+---+---+
404                           *  keyi *
405                     +---+---+---+---+---+
406                        /    |    \
407 index of Child:      i-1    i     i+1
408                      /      |       \
409             +---+---+   +---+---+      +---+---+
410              *   *        *   *          *   *   
411         +---+---+---+   +---+---+---+  +---+---+---+
412         leftSibling       Child        rightSibling 
413 ============================================================*/ 
414     /*二、结点中未找到了关键字key的情况.*/ 
415     else { 
416         BTNode *leftSibling, *rightSibling, *child; 
417         // 3. key 不在内节点 node 中,则应当在某个包含 key 的子节点中。 
418         //  key < node->key[index], 所以 key 应当在孩子节点 node->child[index] 中 
419         child = node->child[index]; 
420         if (!child) { 
421             printf("Failed to remove %c, it is not in the tree!\n", key); 
422             return; 
423         } 
424         /*所需查找的该孩子结点刚脱贫的情况*/ 
425         if (child->keynum == BTree_D - 1) { 
426             leftSibling = NULL; 
427             rightSibling = NULL; 
428    
429             if (index - 1 >= 0) { 
430                 leftSibling = node->child[index - 1]; 
431             } 
432    
433             if (index + 1 <= node->keynum) { 
434                 rightSibling = node->child[index + 1]; 
435             } 
436             /*选择致富的相邻兄弟结点。*/ 
437             // 3a,如果所在孩子节点相邻的兄弟节点中有节点至少包含 BTree_D 个关键字 
438             // 将 node 的一个关键字key[index]下移到 child 中,将相对富有的相邻兄弟节点中一个关键字上移到 
439             // node 中,然后在 child 孩子节点中递归删除 key。 请看M
440             if ((leftSibling && leftSibling->keynum >= BTree_D) 
441                 || (rightSibling && rightSibling->keynum >= BTree_D)) { 
442                 int richR = 0; 
443                 if(rightSibling) richR = 1; 
444                 if(leftSibling && rightSibling) { 
445                     richR = cmp(rightSibling->keynum,leftSibling->keynum); 
446                 } 
447                 if (rightSibling && rightSibling->keynum >= BTree_D && richR) { 
448         //相邻右兄弟相对富有,则该孩子先向父节点借一个元素,右兄弟中的第一个元素上移至父节点所借位置,并进行相应调整。 
449                     child->key[child->keynum] = node->key[index]; 
450                     child->child[child->keynum + 1] = rightSibling->child[0]; 
451                     ++child->keynum; 
452    
453                     node->key[index] = rightSibling->key[0]; 
454    
455                     for (j = 0; j < rightSibling->keynum - 1; ++j) {//元素前移 
456                         rightSibling->key[j] = rightSibling->key[j + 1]; 
457                         rightSibling->child[j] = rightSibling->child[j + 1]; 
458                     } 
459                     rightSibling->key[rightSibling->keynum-1] = 0; 
460                     rightSibling->child[rightSibling->keynum-1] = rightSibling->child[rightSibling->keynum]; 
461                     rightSibling->child[rightSibling->keynum] = NULL; 
462                     --rightSibling->keynum; 
463                 } 
464                 else {//相邻左兄弟相对富有,则该孩子向父节点借一个元素,左兄弟中的最后元素上移至父节点所借位置,并进行相应调整。 
465                     for (j = child->keynum; j > 0; --j) {//元素后移 
466                         child->key[j] = child->key[j - 1]; 
467                         child->child[j + 1] = child->child[j]; 
468                     } 
469                     child->child[1] = child->child[0]; 
470                     child->child[0] = leftSibling->child[leftSibling->keynum]; 
471                     child->key[0] = node->key[index - 1]; 
472                     ++child->keynum; 
473    
474                     node->key[index - 1] = leftSibling->key[leftSibling->keynum - 1]; 
475    
476                     leftSibling->key[leftSibling->keynum - 1] = 0; 
477                     leftSibling->child[leftSibling->keynum] = NULL; 
478    
479                     --leftSibling->keynum; 
480                 } 
481             } 
482             /*相邻兄弟结点都刚脱贫。删除前需要兄弟结点的合并操作,*/ 
483             // 3b, 如果所在孩子节点相邻的兄弟节点都只包含 BTree_D - 1 个关键字, 
484             // 将 child 与其一相邻节点合并,并将 node 中的一个关键字下降到合并节点中, 
485             // 再在 node 中删除那个关键字和相关指针,若 node 的 key 为空,删之,并调整根为合并结点。 
486             // 最后,在相关孩子节点child中递归删除 key。 
487             else if ((!leftSibling || (leftSibling && leftSibling->keynum == BTree_D - 1)) 
488                 && (!rightSibling || (rightSibling && rightSibling->keynum == BTree_D - 1))) { 
489                 if (leftSibling && leftSibling->keynum == BTree_D - 1) { 
490    
491                     BTree_merge_child(tree, node, index - 1);//node中的右孩子元素合并到左孩子中。 
492    
493                     child = leftSibling; 
494                 } 
495    
496                 else if (rightSibling && rightSibling->keynum == BTree_D - 1) { 
497    
498                     BTree_merge_child(tree, node, index);//node中的右孩子元素合并到左孩子中。 
499                 } 
500             } 
501         } 
502    
503         BTree_recursive_remove(&child, key);//调整后,在key所在孩子结点中继续递归删除key。 
504     } 
505 } 
506    
507 void BTree_remove(BTree* tree, KeyType key) 
508 { 
509 #ifdef DEBUG_BTREE 
510     printf("BTree_remove:\n"); 
511 #endif 
512     if (*tree==NULL) 
513     {    
514         printf("BTree is NULL!\n"); 
515         return; 
516     } 
517    
518     BTree_recursive_remove(tree, key); 
519 } 
520    
521 //=====================================search==================================== 
522    
523 BTNode* BTree_recursive_search(const BTree tree, KeyType key, int* pos) 
524 { 
525     int i = 0; 
526    
527     while (i < tree->keynum && key > tree->key[i]) { 
528         ++i; 
529     } 
530    
531     // Find the key. 
532     if (i < tree->keynum && tree->key[i] == key) { 
533         *pos = i; 
534         return tree; 
535     } 
536    
537     // tree 为叶子节点,找不到 key,查找失败返回 
538     if (tree->isLeaf) { 
539         return NULL; 
540     } 
541    
542     // 节点内查找失败,但 tree->key[i - 1]< key < tree->key[i], 
543     // 下一个查找的结点应为 child[i] 
544    
545     // 从磁盘读取第 i 个孩子的数据 
546     disk_read(&tree->child[i]); 
547    
548     // 递归地继续查找于树 tree->child[i] 
549     return BTree_recursive_search(tree->child[i], key, pos); 
550 } 
551    
552 BTNode* BTree_search(const BTree tree, KeyType key, int* pos) 
553 { 
554 #ifdef DEBUG_BTREE 
555     printf("BTree_search:\n"); 
556 #endif 
557     if (!tree) { 
558         printf("BTree is NULL!\n"); 
559         return NULL; 
560     } 
561     *pos = -1; 
562     return BTree_recursive_search(tree,key,pos); 
563 } 
564    
565 //===============================create=============================== 
566 void BTree_create(BTree* tree, const KeyType* data, int length) 
567 { 
568     assert(tree); 
569    
570     int i; 
571    
572 #ifdef DEBUG_BTREE 
573     printf("\n 开始创建 B-树,关键字为:\n"); 
574     for (i = 0; i < length; i++) { 
575         printf(" %c ", data[i]); 
576     } 
577     printf("\n"); 
578 #endif 
579    
580     for (i = 0; i < length; i++) { 
581 #ifdef DEBUG_BTREE 
582         printf("\n插入关键字 %c:\n", data[i]); 
583 #endif 
584         int pos = -1; 
585         BTree_search(*tree,data[i],&pos);//树的递归搜索,查看data[i]是否在树中,在树里,pos改为0。 
586         if (pos!=-1) 
587         { 
588             printf("this key %c is in the B-tree,not to insert.\n",data[i]); 
589         }else{ 
590             BTree_insert(tree, data[i]);//插入元素到BTree中。 
591         } 
592    
593 #ifdef DEBUG_BTREE 
594         BTree_print(*tree);//树的深度遍历。 
595 #endif 
596     } 
597    
598     printf("\n"); 
599 } 
600 //===============================destroy=============================== 
601 void BTree_destroy(BTree* tree) 
602 { 
603     int i; 
604     BTNode* node = *tree; 
605    
606     if (node) { 
607         for (i = 0; i <= node->keynum; i++) { 
608             BTree_destroy(&node->child[i]); 
609         } 
610    
611         free(node); 
612     } 
613    
614     *tree = NULL; 
615 } 
616  
617  
618 //测试order序(阶)的B-TREE结构基本操作。 
619 //查找:search,插入:insert,删除:remove。 
620 //创建:create,销毁:destory,打印:print。 
621    
622 #include <stdio.h> 
623 #include "btree.h" 
624    
625 void test_BTree_search(BTree tree, KeyType key) 
626 { 
627     int pos = -1; 
628     BTNode*    node = BTree_search(tree, key, &pos); 
629     if (node) { 
630         printf("在%s节点(包含 %d 个关键字)中找到关键字 %c,其索引为 %d\n", 
631             node->isLeaf ? "叶子" : "非叶子", 
632             node->keynum, key, pos); 
633     } 
634     else { 
635         printf("在树中找不到关键字 %c\n", key); 
636     } 
637 } 
638    
639 void test_BTree_remove(BTree* tree, KeyType key) 
640 { 
641     printf("\n移除关键字 %c \n", key); 
642     BTree_remove(tree, key); 
643     BTree_print(*tree); 
644     printf("\n"); 
645 } 

test_BTree.c文件代码:

  1 #include "btree.h"
  2 
  3 
  4 void test_btree() 
  5 { 
  6    
  7     KeyType array[] = { 
  8         'G','G', 'M', 'P', 'X', 'A', 'C', 'D', 'E', 'J', 'K', 
  9         'N', 'O', 'R', 'S', 'T', 'U', 'V', 'Y', 'Z', 'F', 'X' 
 10     }; 
 11     //KeyType array[] = {'A','B','C','D','E','F','G','H','I','J'};
 12     const int length = sizeof(array)/sizeof(KeyType); 
 13     BTree tree = NULL; 
 14     BTNode* node = NULL; 
 15     int pos = -1; 
 16     KeyType key1 = 'R';        // in the tree. 
 17     KeyType key2 = 'B';        // not in the tree. 
 18      
 19     // 创建 
 20     BTree_create(&tree, array, length); 
 21    
 22     printf("\n=== 创建 B- 树 ===\n"); 
 23     BTree_print(tree); 
 24     printf("\n"); 
 25    
 26     // 查找 
 27     test_BTree_search(tree, key1); 
 28     printf("\n"); 
 29     test_BTree_search(tree, key2); 
 30    
 31     // 移除不在B树中的元素 
 32     test_BTree_remove(&tree, key2); 
 33     printf("\n"); 
 34    
 35     // 插入关键字 
 36     printf("\n插入关键字 %c \n", key2); 
 37     BTree_insert(&tree, key2); 
 38     BTree_print(tree); 
 39     printf("\n"); 
 40    
 41     test_BTree_search(tree, key2); 
 42    
 43     // 移除关键字 
 44     test_BTree_remove(&tree, key2); 
 45     test_BTree_search(tree, key2); 
 46     BTree_print(tree);
 47  
 48     key2 = 'M'; 
 49     test_BTree_remove(&tree, key2); 
 50     test_BTree_search(tree, key2); 
 51     BTree_print(tree);
 52  
 53     key2 = 'E'; 
 54     test_BTree_remove(&tree, key2); 
 55     test_BTree_search(tree, key2); 
 56     BTree_print(tree);
 57  
 58     key2 = 'G'; 
 59     test_BTree_remove(&tree, key2); 
 60     test_BTree_search(tree, key2); 
 61     BTree_print(tree);
 62  
 63     key2 = 'A'; 
 64     test_BTree_remove(&tree, key2); 
 65     test_BTree_search(tree, key2); 
 66     BTree_print(tree);
 67  
 68     key2 = 'D'; 
 69     test_BTree_remove(&tree, key2); 
 70     test_BTree_search(tree, key2); 
 71     BTree_print(tree);
 72  
 73     key2 = 'K'; 
 74     test_BTree_remove(&tree, key2); 
 75     test_BTree_search(tree, key2); 
 76     BTree_print(tree);
 77  
 78     key2 = 'P'; 
 79     test_BTree_remove(&tree, key2); 
 80     test_BTree_search(tree, key2); 
 81     BTree_print(tree);
 82  
 83     key2 = 'J'; 
 84     test_BTree_remove(&tree, key2); 
 85     test_BTree_search(tree, key2); 
 86     BTree_print(tree);
 87  
 88     key2 = 'C'; 
 89     test_BTree_remove(&tree, key2); 
 90     test_BTree_search(tree, key2); 
 91     BTree_print(tree);
 92  
 93     key2 = 'X'; 
 94     test_BTree_remove(&tree, key2); 
 95     test_BTree_search(tree, key2); 
 96     BTree_print(tree);
 97  
 98     key2 = 'O'; 
 99     test_BTree_remove(&tree, key2); 
100     test_BTree_search(tree, key2); 
101     BTree_print(tree);
102  
103     key2 = 'V'; 
104     test_BTree_remove(&tree, key2); 
105     test_BTree_search(tree, key2); 
106     BTree_print(tree);
107  
108     key2 = 'R'; 
109     test_BTree_remove(&tree, key2); 
110     test_BTree_search(tree, key2); 
111     BTree_print(tree);
112  
113     key2 = 'U'; 
114     test_BTree_remove(&tree, key2); 
115     test_BTree_search(tree, key2); 
116     BTree_print(tree);
117  
118     key2 = 'T'; 
119     test_BTree_remove(&tree, key2); 
120     test_BTree_search(tree, key2); 
121     BTree_print(tree);
122  
123     key2 = 'N'; 
124     test_BTree_remove(&tree, key2); 
125     test_BTree_search(tree, key2);
126     BTree_print(tree);
127  
128     key2 = 'S'; 
129     test_BTree_remove(&tree, key2); 
130     test_BTree_search(tree, key2); 
131     BTree_print(tree);
132  
133     key2 = 'Y'; 
134     test_BTree_remove(&tree, key2); 
135     test_BTree_search(tree, key2); 
136     BTree_print(tree);
137  
138     key2 = 'F'; 
139     test_BTree_remove(&tree, key2); 
140     test_BTree_search(tree, key2);
141     BTree_print(tree);
142  
143     key2 = 'Z'; 
144     test_BTree_remove(&tree, key2); 
145     test_BTree_search(tree, key2); 
146     BTree_print(tree);
147     // 销毁 
148     BTree_destroy(&tree); 
149 }  
150 
151 int main() 
152 { 
153     test_btree(); 
154    
155     return 0; 
156 } 

原文路径:https://www.cnblogs.com/cthon/p/9281664.html。

说明:仅供本人参考学习。

btree.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//实现对order序(阶)的B-TREE结构基本操作的封装。 
//查找:search,插入:insert,删除:remove。 
//创建:create,销毁:destory,打印:print。 
#ifndef BTREE_H 
#define BTREE_H 
   
#ifdef __cplusplus 
extern "C" 
#endif 
   
////* 定义m序(阶)B 树的最小度数BTree_D=ceil(m)*/ 
/// 在这里定义每个节点中关键字的最大数目为:2 * BTree_D - 1,即序(阶):2 * BTree_D. 
#define BTree_D        2 
#define ORDER        (BTree_D * 2) //定义为4阶B-tree,2-3-4树。最简单为3阶B-tree,2-3树。 
//#define ORDER        (BTree_T * 2-1)  //最简单为3阶B-tree,2-3树。 
   
    typedef int KeyType; 
    typedef struct BTNode{ 
        int keynum;                        /// 结点中关键字的个数,keynum <= BTree_N 
        KeyType key[ORDER-1];                /// 关键字向量为key[0..keynum - 1] 
        struct BTNode* child[ORDER];        /// 孩子指针向量为child[0..keynum] 
        bool isLeaf;                    /// 是否是叶子节点的标志 
    }BTNode; 
       
    typedef BTNode* BTree;  ///定义BTree 
       
    ///给定数据集data,创建BTree。 
    void BTree_create(BTree* tree, const KeyType* data, int length); 
   
    ///销毁BTree,释放内存空间。 
    void BTree_destroy(BTree* tree); 
       
    ///在BTree中插入关键字key。 
    void BTree_insert(BTree* tree, KeyType key); 
   
    ///在BTree中移除关键字key。 
    void BTree_remove(BTree* tree, KeyType key); 
   
    ///深度遍历BTree打印各层结点信息。 
    void BTree_print(const BTree tree, int layer=1); 
       
    /// 在BTree中查找关键字 key, 
    /// 成功时返回找到的节点的地址及 key 在其中的位置 *pos 
    /// 失败时返回 NULL 及查找失败时扫描到的节点位置 *pos 
    BTNode* BTree_search(const BTree tree, int key, int* pos); 
       
#ifdef __cplusplus 
#endif 
   
#endif 

  

btree.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
//实现对order序(阶)的B-TREE结构基本操作的封装。 
//查找:search,插入:insert,删除:remove。 
//创建:create,销毁:destory,打印:print。 
#include <stdlib.h> 
#include <stdio.h> 
#include <assert.h> 
#include "btree.h" 
   
//#define max(a, b) (((a) > (b)) ? (a) : (b)) 
#define cmp(a, b) ( ( ((a)-(b)) >= (0) ) ? (1) : (0) ) //比较a,b大小 
#define DEBUG_BTREE 
   
   
// 模拟向磁盘写入节点 
void disk_write(BTNode* node) 
//打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
    printf("向磁盘写入节点"); 
    for(int i=0;i<ORDER-1;i++){ 
        printf("%c",node->key[i]); 
    
    printf("\n"); 
   
// 模拟从磁盘读取节点 
void disk_read(BTNode** node) 
//打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
    printf("向磁盘读取节点"); 
    for(int i=0;i<ORDER-1;i++){ 
        printf("%c",(*node)->key[i]); 
    
    printf("\n"); 
   
// 按层次打印 B 树 
void BTree_print(const BTree tree, int layer) 
    int i; 
    BTNode* node = tree; 
   
    if (node) { 
        printf("第 %d 层, %d node : ", layer, node->keynum); 
   
        //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。 
        for (i = 0; i < ORDER-1; ++i) { 
        //for (i = 0; i < node->keynum; ++i) { 
            printf("%c ", node->key[i]); 
        
   
        printf("\n"); 
   
        ++layer; 
        for (i = 0 ; i <= node->keynum; i++) { 
            if (node->child[i]) { 
                BTree_print(node->child[i], layer); 
            
        
    
    else 
        printf("树为空。\n"); 
    
   
// 结点node内对关键字进行二分查找。 
int binarySearch(BTNode* node, int low, int high, KeyType Fkey) 
    int mid; 
    while (low<=high) 
    
        mid = low + (high-low)/2; 
        if (Fkey<node->key[mid]) 
        
            high = mid-1; 
        
        if (Fkey>node->key[mid]) 
        
            low = mid+1; 
        
        if (Fkey==node->key[mid]) 
        
            return mid;//返回下标。 
        
    
    return 0;//未找到返回0. 
   
 
/***************************************************************************************
   将分裂的结点中的一半元素给新建的结点,并且将分裂结点中的中间关键字元素上移至父节点中。
   parent 是一个非满的父节点
   node 是 tree 孩子表中下标为 index 的孩子节点,且是满的,需分裂。
   分裂确保有序的情况下是均衡的
*******************************************************************/ 
void BTree_split_child(BTNode* parent, int index, BTNode* node) 
#ifdef DEBUG_BTREE 
    printf("BTree_split_child!\n"); 
#endif 
    assert(parent && node); 
    int i; 
   
    // 创建新节点,存储 node 中后半部分的数据 
    BTNode* newNode = (BTNode*)calloc(sizeof(BTNode), 1); 
    if (!newNode) { 
        printf("Error! out of memory!\n"); 
        return
    
   
    newNode->isLeaf = node->isLeaf; 
    newNode->keynum = BTree_D - 1; 
   
    // 拷贝 node 后半部分关键字,然后将node后半部分置为0。 
    for (i = 0; i < newNode->keynum; ++i){ 
        newNode->key[i] = node->key[BTree_D + i]; 
        node->key[BTree_D + i] = 0; 
    
   
    // 如果 node 不是叶子节点,拷贝 node 后半部分的指向孩子节点的指针,然后将node后半部分指向孩子节点的指针置为NULL。 
    if (!node->isLeaf) { 
        for (i = 0; i < BTree_D; i++) { 
            newNode->child[i] = node->child[BTree_D + i]; 
            node->child[BTree_D + i] = NULL; 
        
    
   
    // 将 node 分裂出 newNode 之后,里面的数据减半 
    node->keynum = BTree_D - 1; 
   
    // 调整父节点中的指向孩子的指针和关键字元素。分裂时父节点增加指向孩子的指针和关键元素。 
    for (i = parent->keynum; i > index; --i) { 
        parent->child[i + 1] = parent->child[i]; 
    
   
    parent->child[index + 1] = newNode; 
   
    for (i = parent->keynum - 1; i >= index; --i) { 
        parent->key[i + 1] = parent->key[i]; 
    
   
    parent->key[index] = node->key[BTree_D - 1]; 
    ++parent->keynum; 
   
    node->key[BTree_D - 1] = 0; 
   
    // 写入磁盘 
     disk_write(parent); 
     disk_write(newNode); 
     disk_write(node); 
   
void BTree_insert_nonfull(BTNode* node, KeyType key) 
    assert(node); 
   
    int i; 
   
    // 节点是叶子节点,直接插入,如果比其他值小,那么移动其他值 
    if (node->isLeaf) { 
        i = node->keynum - 1; 
        while (i >= 0 && key < node->key[i]) { 
            node->key[i + 1] = node->key[i]; 
            --i; 
        
   
        node->key[i + 1] = key; 
        ++node->keynum; 
   
        // 写入磁盘 
        disk_write(node); 
    
   
    // 节点是内部节点 
    else 
        /* 查找插入的位置*/ 
        i = node->keynum - 1; 
        while (i >= 0 && key < node->key[i]) { 
            --i; 
        
   
        ++i; 
   
        // 从磁盘读取孩子节点 
        disk_read(&node->child[i]); 
   
        // 如果该孩子节点已满,分裂调整值 
        if (node->child[i]->keynum == (ORDER-1)) { 
            BTree_split_child(node, i, node->child[i]); 
            // 如果待插入的关键字大于该分裂结点中上移到父节点的关键字,在该关键字的右孩子结点中进行插入操作。 
            if (key > node->key[i]) { 
                ++i; 
            
        
        BTree_insert_nonfull(node->child[i], key); 
    
   
void BTree_insert(BTree* tree, KeyType key) 
#ifdef DEBUG_BTREE 
    printf("BTree_insert:\n"); 
#endif 
    BTNode* node; 
    BTNode* root = *tree; 
   
    // 树为空 
    if (NULL == root) { 
        root = (BTNode*)calloc(sizeof(BTNode), 1); 
        if (!root) { 
            printf("Error! out of memory!\n"); 
            return
        
        root->isLeaf = true
        root->keynum = 1; 
        root->key[0] = key; 
   
        *tree = root; 
   
        // 写入磁盘 
        disk_write(root); 
   
        return
    
   
    // 根节点已满,插入前需要进行分裂调整 
    if (root->keynum == (ORDER-1)) { 
        // 产生新节点当作根 
        node = (BTNode*)calloc(sizeof(BTNode), 1); 
        if (!node) { 
            printf("Error! out of memory!\n"); 
            return
        
   
        *tree = node; 
        node->isLeaf = false
        node->keynum = 0; 
        node->child[0] = root; 
   
        BTree_split_child(node, 0, root); 
   
        BTree_insert_nonfull(node, key); 
    
   
    // 根节点未满,在当前节点中插入 key 
    else 
        BTree_insert_nonfull(root, key); 
    
}
// 对 tree 中的节点 node 进行合并孩子节点处理. 
// 注意:孩子节点的 keynum 必须均已达到下限,即均等于 BTree_D - 1 
// 将 tree 中索引为 index 的 key 下移至左孩子结点中, 
// 将 node 中索引为 index + 1 的孩子节点合并到索引为 index 的孩子节点中,右孩子合并到左孩子结点中。 
// 并调相关的 key 和指针。
void BTree_merge_child(BTree* tree, BTNode* node, int index) 
{
#ifdef DEBUG_BTREE 
    printf("BTree_merge_child!\n"); 
#endif 
    assert(tree && node && index >= 0 && index < node->keynum); 
   
    int i; 
   
    KeyType key = node->key[index]; 
    BTNode* leftChild = node->child[index]; 
    BTNode* rightChild = node->child[index + 1]; 
   
    assert(leftChild && leftChild->keynum == BTree_D - 1 
        && rightChild && rightChild->keynum == BTree_D - 1); 
   
    // 将 node中关键字下标为index 的 key 下移至左孩子结点中,该key所对应的右孩子结点指向node的右孩子结点中的第一个孩子。 
    leftChild->key[leftChild->keynum] = key; 
    leftChild->child[leftChild->keynum + 1] = rightChild->child[0]; 
    ++leftChild->keynum; 
   
    // 右孩子的元素合并到左孩子结点中。 
    for (i = 0; i < rightChild->keynum; ++i) { 
        leftChild->key[leftChild->keynum] = rightChild->key[i]; 
        leftChild->child[leftChild->keynum + 1] = rightChild->child[i + 1]; 
        ++leftChild->keynum; 
    
   
    // 在 node 中下移的 key后面的元素前移 
    for (i = index; i < node->keynum - 1; ++i) { 
        node->key[i] = node->key[i + 1]; 
        node->child[i + 1] = node->child[i + 2]; 
    
    node->key[node->keynum - 1] = 0; 
    node->child[node->keynum] = NULL; 
    --node->keynum; 
   
    // 如果根节点没有 key 了,并将根节点调整为合并后的左孩子节点;然后删除释放空间。 
    if (node->keynum == 0) { 
        if (*tree == node) { 
            *tree = leftChild; 
        
   
        free(node); 
        node = NULL; 
    
   
    free(rightChild); 
    rightChild = NULL; 
   
void BTree_recursive_remove(BTree* tree, KeyType key) 
    // B-数的保持条件之一: 
    // 非根节点的内部节点的关键字数目不能少于 BTree_D - 1 
   
    int i, j, index; 
    BTNode *root = *tree; 
    BTNode *node = root; 
   
    if (!root) { 
        printf("Failed to remove %c, it is not in the tree!\n", key); 
        return
    
   
    // 结点中找key。 
    index = 0; 
    while (index < node->keynum && key > node->key[index]) { 
        ++index; 
    
   
/*======================含有key的当前结点时的情况====================
node:
index of Key:            i-1  i  i+1
                        +---+---+---+---+
                          *  key   *
                    +---+---+---+---+---+
                           /     \
index of Child:           i      i+1
                         /         \
                    +---+---+      +---+---+
                      *   *           *   *   
                +---+---+---+  +---+---+---+
                    leftChild     rightChild
============================================================*/ 
    /*一、结点中找到了关键字key的情况.*/ 
    BTNode *leftChild, *rightChild; 
    KeyType leftKey, rightKey; 
    if (index < node->keynum && node->key[index] == key) { 
        /* 1,所在节点是叶子节点,直接删除*/ 
        if (node->isLeaf) { 
            for (i = index; i < node->keynum-1; ++i) { 
                node->key[i] = node->key[i + 1]; 
                //node->child[i + 1] = node->child[i + 2];叶子节点的孩子结点为空,无需移动处理。 
            
            node->key[node->keynum-1] = 0; 
            //node->child[node->keynum] = NULL; 
            --node->keynum; 
   
            if (node->keynum == 0) { 
                assert(node == *tree); 
                free(node); 
                *tree = NULL; 
            
   
            return
        
        /*2.选择脱贫致富的孩子结点。*/ 
        // 2a,选择相对富有的左孩子结点。 
        // 如果位于 key 前的左孩子结点的 key 数目 >= BTree_D, 
        // 在其中找 key 的左孩子结点的最后一个元素上移至父节点key的位置。 
        // 然后在左孩子节点中递归删除元素leftKey。 
        else if (node->child[index]->keynum >= BTree_D) { 
            leftChild = node->child[index]; 
            leftKey = leftChild->key[leftChild->keynum - 1]; 
            node->key[index] = leftKey; 
   
            BTree_recursive_remove(&leftChild, leftKey); 
        
        // 2b,选择相对富有的右孩子结点。 
        // 如果位于 key 后的右孩子结点的 key 数目 >= BTree_D, 
        // 在其中找 key 的右孩子结点的第一个元素上移至父节点key的位置 
        // 然后在右孩子节点中递归删除元素rightKey。 
        else if (node->child[index + 1]->keynum >= BTree_D) { 
            rightChild = node->child[index + 1]; 
            rightKey = rightChild->key[0]; 
            node->key[index] = rightKey; 
   
            BTree_recursive_remove(&rightChild, rightKey); 
        
        /*左右孩子结点都刚脱贫。删除前需要孩子结点的合并操作*/ 
        // 2c,左右孩子结点只包含 BTree_D - 1 个节点, 
        // 合并是将 key 下移至左孩子节点,并将右孩子节点合并到左孩子节点中, 
        // 删除右孩子节点,在父节点node中移除 key 和指向右孩子节点的指针, 
        // 然后在合并了的左孩子节点中递归删除元素key。 
        else if (node->child[index]->keynum == BTree_D - 1 
            && node->child[index + 1]->keynum == BTree_D - 1){ 
            leftChild = node->child[index]; 
   
            BTree_merge_child(tree, node, index); 
   
            // 在合并了的左孩子节点中递归删除 key 
            BTree_recursive_remove(&leftChild, key); 
        
    
   
/*======================未含有key的当前结点时的情况====================
node:
index of Key:            i-1  i  i+1
                        +---+---+---+---+
                          *  keyi *
                    +---+---+---+---+---+
                       /    |    \
index of Child:      i-1    i     i+1
                     /      |       \
            +---+---+   +---+---+      +---+---+
             *   *        *   *          *   *   
        +---+---+---+   +---+---+---+  +---+---+---+
        leftSibling       Child        rightSibling 
============================================================*/ 
    /*二、结点中未找到了关键字key的情况.*/ 
    else 
        BTNode *leftSibling, *rightSibling, *child; 
        // 3. key 不在内节点 node 中,则应当在某个包含 key 的子节点中。 
        //  key < node->key[index], 所以 key 应当在孩子节点 node->child[index] 中 
        child = node->child[index]; 
        if (!child) { 
            printf("Failed to remove %c, it is not in the tree!\n", key); 
            return
        
        /*所需查找的该孩子结点刚脱贫的情况*/ 
        if (child->keynum == BTree_D - 1) { 
            leftSibling = NULL; 
            rightSibling = NULL; 
   
            if (index - 1 >= 0) { 
                leftSibling = node->child[index - 1]; 
            
   
            if (index + 1 <= node->keynum) { 
                rightSibling = node->child[index + 1]; 
            
            /*选择致富的相邻兄弟结点。*/ 
            // 3a,如果所在孩子节点相邻的兄弟节点中有节点至少包含 BTree_D 个关键字 
            // 将 node 的一个关键字key[index]下移到 child 中,将相对富有的相邻兄弟节点中一个关键字上移到 
            // node 中,然后在 child 孩子节点中递归删除 key。 请看M
            if ((leftSibling && leftSibling->keynum >= BTree_D) 
                || (rightSibling && rightSibling->keynum >= BTree_D)) { 
                int richR = 0; 
                if(rightSibling) richR = 1; 
                if(leftSibling && rightSibling) { 
                    richR = cmp(rightSibling->keynum,leftSibling->keynum); 
                
                if (rightSibling && rightSibling->keynum >= BTree_D && richR) { 
        //相邻右兄弟相对富有,则该孩子先向父节点借一个元素,右兄弟中的第一个元素上移至父节点所借位置,并进行相应调整。 
                    child->key[child->keynum] = node->key[index]; 
                    child->child[child->keynum + 1] = rightSibling->child[0]; 
                    ++child->keynum; 
   
                    node->key[index] = rightSibling->key[0]; 
   
                    for (j = 0; j < rightSibling->keynum - 1; ++j) {//元素前移 
                        rightSibling->key[j] = rightSibling->key[j + 1]; 
                        rightSibling->child[j] = rightSibling->child[j + 1]; 
                    
                    rightSibling->key[rightSibling->keynum-1] = 0; 
                    rightSibling->child[rightSibling->keynum-1] = rightSibling->child[rightSibling->keynum]; 
                    rightSibling->child[rightSibling->keynum] = NULL; 
                    --rightSibling->keynum; 
                
                else {//相邻左兄弟相对富有,则该孩子向父节点借一个元素,左兄弟中的最后元素上移至父节点所借位置,并进行相应调整。 
                    for (j = child->keynum; j > 0; --j) {//元素后移 
                        child->key[j] = child->key[j - 1]; 
                        child->child[j + 1] = child->child[j]; 
                    
                    child->child[1] = child->child[0]; 
                    child->child[0] = leftSibling->child[leftSibling->keynum]; 
                    child->key[0] = node->key[index - 1]; 
                    ++child->keynum; 
   
                    node->key[index - 1] = leftSibling->key[leftSibling->keynum - 1]; 
   
                    leftSibling->key[leftSibling->keynum - 1] = 0; 
                    leftSibling->child[leftSibling->keynum] = NULL; 
   
                    --leftSibling->keynum; 
                
            
            /*相邻兄弟结点都刚脱贫。删除前需要兄弟结点的合并操作,*/ 
            // 3b, 如果所在孩子节点相邻的兄弟节点都只包含 BTree_D - 1 个关键字, 
            // 将 child 与其一相邻节点合并,并将 node 中的一个关键字下降到合并节点中, 
            // 再在 node 中删除那个关键字和相关指针,若 node 的 key 为空,删之,并调整根为合并结点。 
            // 最后,在相关孩子节点child中递归删除 key。 
            else if ((!leftSibling || (leftSibling && leftSibling->keynum == BTree_D - 1)) 
                && (!rightSibling || (rightSibling && rightSibling->keynum == BTree_D - 1))) { 
                if (leftSibling && leftSibling->keynum == BTree_D - 1) { 
   
                    BTree_merge_child(tree, node, index - 1);//node中的右孩子元素合并到左孩子中。 
   
                    child = leftSibling; 
                
   
                else if (rightSibling && rightSibling->keynum == BTree_D - 1) { 
   
                    BTree_merge_child(tree, node, index);//node中的右孩子元素合并到左孩子中。 
                
            
        
   
        BTree_recursive_remove(&child, key);//调整后,在key所在孩子结点中继续递归删除key。 
    
   
void BTree_remove(BTree* tree, KeyType key) 
#ifdef DEBUG_BTREE 
    printf("BTree_remove:\n"); 
#endif 
    if (*tree==NULL) 
    {    
        printf("BTree is NULL!\n"); 
        return
    
   
    BTree_recursive_remove(tree, key); 
   
//=====================================search==================================== 
   
BTNode* BTree_recursive_search(const BTree tree, KeyType key, int* pos) 
    int i = 0; 
   
    while (i < tree->keynum && key > tree->key[i]) { 
        ++i; 
    
   
    // Find the key. 
    if (i < tree->keynum && tree->key[i] == key) { 
        *pos = i; 
        return tree; 
    
   
    // tree 为叶子节点,找不到 key,查找失败返回 
    if (tree->isLeaf) { 
        return NULL; 
    
   
    // 节点内查找失败,但 tree->key[i - 1]< key < tree->key[i], 
    // 下一个查找的结点应为 child[i] 
   
    // 从磁盘读取第 i 个孩子的数据 
    disk_read(&tree->child[i]); 
   
    // 递归地继续查找于树 tree->child[i] 
    return BTree_recursive_search(tree->child[i], key, pos); 
   
BTNode* BTree_search(const BTree tree, KeyType key, int* pos) 
#ifdef DEBUG_BTREE 
    printf("BTree_search:\n"); 
#endif 
    if (!tree) { 
        printf("BTree is NULL!\n"); 
        return NULL; 
    
    *pos = -1; 
    return BTree_recursive_search(tree,key,pos); 
   
//===============================create=============================== 
void BTree_create(BTree* tree, const KeyType* data, int length) 
    assert(tree); 
   
    int i; 
   
#ifdef DEBUG_BTREE 
    printf("\n 开始创建 B-树,关键字为:\n"); 
    for (i = 0; i < length; i++) { 
        printf(" %c ", data[i]); 
    
    printf("\n"); 
#endif 
   
    for (i = 0; i < length; i++) { 
#ifdef DEBUG_BTREE 
        printf("\n插入关键字 %c:\n", data[i]); 
#endif 
        int pos = -1; 
        BTree_search(*tree,data[i],&pos);//树的递归搜索,查看data[i]是否在树中,在树里,pos改为0。 
        if (pos!=-1) 
        
            printf("this key %c is in the B-tree,not to insert.\n",data[i]); 
        }else
            BTree_insert(tree, data[i]);//插入元素到BTree中。 
        
   
#ifdef DEBUG_BTREE 
        BTree_print(*tree);//树的深度遍历。 
#endif 
    
   
    printf("\n"); 
//===============================destroy=============================== 
void BTree_destroy(BTree* tree) 
    int i; 
    BTNode* node = *tree; 
   
    if (node) { 
        for (i = 0; i <= node->keynum; i++) { 
            BTree_destroy(&node->child[i]); 
        
   
        free(node); 
    
   
    *tree = NULL; 
 
 
//测试order序(阶)的B-TREE结构基本操作。 
//查找:search,插入:insert,删除:remove。 
//创建:create,销毁:destory,打印:print。 
   
#include <stdio.h> 
#include "btree.h" 
   
void test_BTree_search(BTree tree, KeyType key) 
    int pos = -1; 
    BTNode*    node = BTree_search(tree, key, &pos); 
    if (node) { 
        printf("在%s节点(包含 %d 个关键字)中找到关键字 %c,其索引为 %d\n"
            node->isLeaf ? "叶子" "非叶子"
            node->keynum, key, pos); 
    
    else 
        printf("在树中找不到关键字 %c\n", key); 
    
   
void test_BTree_remove(BTree* tree, KeyType key) 
    printf("\n移除关键字 %c \n", key); 
    BTree_remove(tree, key); 
    BTree_print(*tree); 
    printf("\n"); 
   

  

test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "btree.h"<br><br>void test_btree() 
   
    KeyType array[] = { 
        'G','G''M''P''X''A''C''D''E''J''K'
        'N''O''R''S''T''U''V''Y''Z''F''X' 
    }; 
    //KeyType array[] = {'A','B','C','D','E','F','G','H','I','J'};
    const int length = sizeof(array)/sizeof(KeyType); 
    BTree tree = NULL; 
    BTNode* node = NULL; 
    int pos = -1; 
    KeyType key1 = 'R';        // in the tree. 
    KeyType key2 = 'B';        // not in the tree. 
     
    // 创建 
    BTree_create(&tree, array, length); 
   
    printf("\n=== 创建 B- 树 ===\n"); 
    BTree_print(tree); 
    printf("\n"); 
   
    // 查找 
    test_BTree_search(tree, key1); 
    printf("\n"); 
    test_BTree_search(tree, key2); 
   
    // 移除不在B树中的元素 
    test_BTree_remove(&tree, key2); 
    printf("\n"); 
   
    // 插入关键字 
    printf("\n插入关键字 %c \n", key2); 
    BTree_insert(&tree, key2); 
    BTree_print(tree); 
    printf("\n"); 
   
    test_BTree_search(tree, key2); 
   
    // 移除关键字 
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'M'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'E'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'G'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'A'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'D'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'K'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'P'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'J'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'C'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'X'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'O'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'V'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'R'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'U'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'T'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'N'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2);
    BTree_print(tree);
 
    key2 = 'S'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'Y'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
 
    key2 = 'F'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2);
    BTree_print(tree);
 
    key2 = 'Z'
    test_BTree_remove(&tree, key2); 
    test_BTree_search(tree, key2); 
    BTree_print(tree);
    // 销毁 
    BTree_destroy(&tree); 
}  <br><br>int main() 
    test_btree(); 
   
    return 0;