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; } |