B樹——思路、及C語言程式碼的實現
阿新 • • 發佈:2018-12-23
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<time.h> 5 #define BTREELENGTH 50 6 #define BTLEN (sizeof(BTNode)) 7 #define MAXINT 100 8 typedef enum status 9 { 10 TRUE, 11 FALSE, 12 OK, 13ERROR, 14 OVERFLOW, 15 EMPTY 16 }Status; 17 typedef int KeyType; 18 19 //**********************************B樹**************************************** 20 #define m 3 // B樹的階,此設為4 21 typedef struct 22 { 23 KeyType key; 24 char data; 25 } Record; 26 typedef structBTNode 27 { 28 int keynum; // 結點中關鍵字個數,即結點的大小 29 struct BTNode *parent; // 指向雙親結點 30 KeyType key[m + 1]; // 關鍵字向量,0號單元未用 31 struct BTNode *ptr[m + 1]; // 子樹指標向量 32 // Record *recptr[m + 1]; // 記錄指標向量,0號單元未用 33 //在此新增其他自定義資料 34 } BTNode, *BTree; // B樹結點和B樹的型別 35 typedef struct 36 { 37 BTNode *pt; // 指向找到的結點 38 int i; // 1..m,在結點中的關鍵字序號 39 int tag; // 1:查詢成功,0:查詢失敗 40 } Result; // 在B樹的查詢結果型別 41 //**********************************B樹**************************************** 42 43 //**********************************佇列*************************************** 44 typedef struct LNode { 45 BTree data; // 資料域 46 struct LNode *next; // 指標域 47 } LNode, *LinkList; 48 //**********************************佇列*************************************** 49 50 /*** 51 * @name Status InitQueue_L(LinkList &L) 52 * @description 初始化佇列 53 * @return 成功返回OK,開闢空間失敗返回OVERFLOW 54 * @notice 55 ***/ 56 Status InitQueue_L(LinkList &L) 57 { // 初始化一個只含頭結點的空單鏈表L 58 if (NULL == (L = (LNode*)malloc(sizeof(LNode)))) // 生成新結點 59 return OVERFLOW; 60 L->next = NULL; 61 return OK; 62 } 63 /*** 64 * @name LNode* MakeNode_L(BTree e) 65 * @description 構造佇列結點 66 * @return 返回結點地址 67 * @notice 68 ***/ 69 LNode* MakeNode_L(BTree e) 70 { // 構造資料域為e的單鏈表結點 71 LNode *p; 72 p = (LNode*)malloc(sizeof(LNode)); // 分配結點空間 73 if (p != NULL) 74 { 75 p->data = e; 76 p->next = NULL; 77 } 78 return p; 79 } 80 /*** 81 * @name Status Enqueue_L(LNode *p, BTree e) 82 * @description 佇列的入隊 83 * @return 成功返回OK,否則返回ERROR 84 * @notice 85 ***/ 86 Status Enqueue_L(LNode *p, BTree e) 87 { //在p結點之後插入q結點 88 if (NULL == p) return ERROR; // 引數不合理 89 while (p->next != NULL) 90 p = p->next; 91 p->next = MakeNode_L(e); // 對應圖4.11(b)的②,修改p結點的指標域 92 return OK; 93 } 94 95 /*** 96 * @name Status Dequeue_L(LNode *p, BTree &e) 97 * @description 佇列的出隊 98 * @return 成功返回OK,否則返回ERROR 99 * @notice 100 ***/ 101 Status Dequeue_L(LNode *p, BTree &e) 102 { 103 // 刪除p結點的直接後繼結點並用引數e返回被刪結點的值 104 LNode *q; 105 if (NULL == p || NULL == p->next) return ERROR; // 刪除位置不合理 106 q = p->next; 107 p->next = q->next; // 修改被刪結點q的指標域 108 e = q->data; 109 free(q); // 釋放結點q 110 return OK; 111 } 112 113 /*** 114 * @name void DestroyQueue(LinkList L) 115 * @description 佇列的銷燬 116 * @return 無返回 117 * @notice 118 ***/ 119 void DestroyQueue(LinkList L) 120 { 121 // 銷燬整個連結串列 122 LinkList p; 123 if (L != NULL) 124 { 125 p = L; 126 L = L->next; 127 free(p); 128 DestroyQueue(L); 129 } 130 } 131 /*** 132 * @name Status IfEmpty(LinkList L) 133 * @description 判斷佇列是否為空 134 * @return 空返回TRUE,不空返回FALSE,否則返回ERROR 135 * @notice 136 ***/ 137 Status IfEmpty(LinkList L) 138 { 139 if (L == NULL) return ERROR; 140 if (L->next == NULL) return TRUE; 141 return FALSE; 142 } 143 /*** 144 * @name Status ergodic(BTree T, LinkList L, int newline, int sum) 145 * @description print需要用到的遞迴遍歷程式 146 * @return 成功返回OK 147 * @notice 此處用到佇列 148 ***/ 149 Status ergodic(BTree T, LinkList L, int newline, int sum) 150 { 151 int index; 152 BTree p; 153 if (T != NULL) 154 { 155 printf("[ "); 156 Enqueue_L(L, T->ptr[0]); 157 for (index = 1;index <= T->keynum; index++) 158 { 159 printf("%d ", T->key[index]); 160 Enqueue_L(L, T->ptr[index]); 161 } 162 sum += T->keynum + 1; 163 printf("]"); 164 if (newline == 0) 165 { 166 printf("\n"); 167 newline = sum - 1; 168 sum = 0; 169 } 170 else 171 { 172 --newline; 173 } 174 } 175 if (IfEmpty(L) == FALSE) 176 { 177 Dequeue_L(L, p); 178 ergodic(p, L, newline, sum); 179 } 180 return OK; 181 } 182 /*** 183 * @name Status print(BTree T) 184 * @description 層次遍歷並分層輸出B樹 185 * @return 成功返回OK 186 * @notice 187 ***/ 188 Status print(BTree T) 189 { 190 LinkList L; 191 if (T == NULL) 192 { 193 printf("[ ]\n"); 194 return OK; 195 } 196 InitQueue_L(L); 197 ergodic(T, L, 0, 0); 198 DestroyQueue(L); 199 return OK; 200 } 201 202 /*** 203 * @name Status findMax(BTree T, BTree &p,int ans) 204 * @description 尋找最大關鍵字的結點,T為要尋找的樹,p為返回的節點,ans為第幾個 205 * @return 成功返回OK,否則返回ERROR 206 * @notice 207 ***/ 208 Status findMax(BTree T, BTree &p, int &ans) 209 { 210 if (T == NULL) 211 return ERROR; 212 p = T; 213 while (p->ptr[p->keynum] != NULL) 214 { 215 p = p->ptr[p->keynum]; 216 } 217 ans = p->keynum; 218 return OK; 219 } 220 /*** 221 * @name Status findMin(BTree T, BTree &p,int ans) 222 * @description 尋找最小關鍵字的結點,T為要尋找的樹,p為返回的節點,ans為第幾個 223 * @return 成功返回OK,否則返回ERROR 224 * @notice 225 ***/ 226 /*** 227 * @name Status findBTree(BTree T, BTree &p, int &ans, KeyType k) 228 * @description 尋找 ,T為要尋找的樹,p為返回的節點,ans為第幾個元素,k為要找的值 229 * @return 成功返回OK,否則返回ERROR 230 * @notice 231 ***/ 232 Status findBTree(BTree T, BTree &p, int &ans, KeyType k) 233 { 234 BTree q; 235 int index = 1; 236 KeyType keynow; 237 if (T == NULL) 238 return ERROR; 239 q = T; 240 keynow = T->key[1]; 241 while (q != NULL) //深度的遍歷 242 { 243 index = 1; 244 keynow = q->key[index]; 245 while (index <= q->keynum) //節點內對各真值進行遍歷 246 { 247 if (k == keynow) //找到元素 248 { 249 p = q; 250 ans = index; 251 return TRUE; 252 } 253 if (k > keynow) 254 { 255 if (index == q->keynum) 256 { 257 if (q->ptr[index] == NULL) 258 { 259 p = q; 260 ans = q->keynum + 1; 261 return FALSE; 262 } 263 q = q->ptr[index]; 264 break; 265 } 266 ++index; 267 keynow = q->key[index]; 268 continue; 269 } 270 if (k < keynow) 271 { 272 if (q->ptr[index - 1] == NULL) 273 { 274 p = q; 275 ans = index; 276 return FALSE; 277 } 278 q = q->ptr[index - 1]; 279 break; 280 } 281 } 282 } 283 284 return ERROR; 285 } 286 /*** 287 * @name Status renewParent(BTree p) 288 * @description 告訴孩子們親身爸爸是誰 289 * @return 成功返回OK,否則返回ERROR 290 * @notice 291 ***/ 292 Status renewParent(BTree p) 293 { 294 int index; 295 if (p == NULL) return ERROR; 296 for (index = 0;index <= p->keynum;++index) 297 { 298 if (p->ptr[index] != NULL) 299 { 300 p->ptr[index]->parent = p; 301 renewParent(p->ptr[index]); 302 } 303 } 304 return OK; 305 } 306 /*** 307 * @name int whichSon(BTree T) 308 * @description 找出是父親的第幾個孩子 309 * @return 成功返回第幾個孩子,否則返回-1 310 * @notice 311 ***/ 312 int whichSon(BTree T) 313 { 314 int index = -1; 315 if (T == NULL) return -1; 316 for (index = 0;index <= T->parent->keynum;++index) //找出是父親的第幾個孩子 317 { 318 if (T->parent->ptr[index] == T) return index; 319 } 320 return -1; 321 } 322 /*** 323 * @name status splitBTree(BTree T) 324 * @description 遞迴實現分裂節點操作 325 * @return 成功返回OK,否則返回ERROR 326 * @notice 327 ***/ 328 Status splitBTree(BTree T) //此時分裂的節點一定會是超出最大值的。 329 { 330 BTree t1, t2; 331 int index, index_1; 332 if (T->parent == NULL) 333 { 334 t1 = (BTree)malloc(BTLEN); 335 if (NULL == t1) return OVERFLOW; 336 t2 = (BTree)malloc(BTLEN); 337 if (NULL == t2) return OVERFLOW; 338 339 t1->keynum = m / 2; 340 t2->keynum = m - (m / 2) - 1; 341 t1->parent = T; 342 t2->parent = T; 343 for (index = 0;index <= m; ++index) //先全部初始化 344 { 345 t1->ptr[index] = NULL; 346 t1->key[index] = 0; 347 t2->ptr[index] = NULL; 348 t2->key[index] = 0; 349 } 350 for (index = 0;index <= m / 2; ++index) //初始化t1 351 { 352 t1->ptr[index] = T->ptr[index]; 353 t1->key[index] = T->key[index]; 354 } 355 t2->ptr[0] = T->ptr[(m / 2) + 1]; 356 for (index = (m / 2) + 2;index <= m; ++index) //初始化t2 357 { 358 t2->ptr[index - ((m / 2) + 1)] = T->ptr[index]; 359 t2->key[index - ((m / 2) + 1)] = T->key[index]; 360 } 361 T->keynum = 1; 362 T->ptr[0] = t1; 363 T->ptr[1] = t2; 364 T->key[1] = T->key[m / 2 + 1]; 365 for (index = 2;index <= m; ++index) //初始化T 366 { 367 T->ptr[index] = NULL; 368 T->key[index] = 0; 369 } 370 return OK; 371 } 372 373 index = whichSon(T); 374 for (index_1 = T->parent->keynum;index_1 > index;--index_1) //騰出父親的位置 375 { 376 T->parent->ptr[index_1 + 1] = T->parent->ptr[index_1]; 377 T->parent->key[index_1 + 1] = T->parent->key[index_1]; 378 } 379 T->parent->keynum++; 380 T->parent->key[index + 1] = T->key[m / 2 + 1]; 381 t2 = T->parent->ptr[index + 1] = (BTree)malloc(BTLEN); 382 if (NULL == t2) return OVERFLOW; 383 for (index = 0;index <= m; ++index) //先全部初始化 384 { 385 t2->ptr[index] = NULL; 386 t2->key[index] = 0; 387 } 388 t2->keynum = m - (m / 2) - 1; 389 t2->parent = T->parent; 390 t2->ptr[0] = T->ptr[(m / 2) + 1]; 391 for (index = (m / 2) + 2;index <= m; ++index) //初始化t2 392 { 393 t2->ptr[index - ((m / 2) + 1)] = T->ptr[index]; 394 t2->key[index - ((m / 2) + 1)] = T->key[index]; 395 } 396 T->keynum = m / 2; 397 for (index = (m / 2) + 1;index <= m; ++index) //初始化t2 398 { 399 T->ptr[index] = NULL; 400 T->key[index] = 0; 401 } 402 if (T->parent->keynum == m) 403 { 404 splitBTree(T->parent); 405 } 406 return OK; 407 } 408 /*** 409 * @name Status insertBTree(BTree &T, Record e) 410 * @description 插入實現元素的插入 411 * @return 成功返回OK,如果存在則返回FALSE,否則返回ERROR 412 * @notice 413 ***/ 414 Status insertBTree(BTree &T, Record e) 415 { 416 BTree p; 417 int index, temp; 418 Status find_flag; 419 if (NULL == T) 420 { 421 T = (BTree)malloc(BTLEN); 422 if (NULL == T) return OVERFLOW; 423 T->keynum = 1; 424 T->parent = NULL; 425 for (index = 0;index <= m; ++index) 426 { 427 T->ptr[index] = NULL; 428 T->key[index] = 0; 429 } 430 T->key[1] = e.key; 431 return OK; 432 } 433 find_flag = findBTree(T, p, temp, e.key); 434 if (find_flag == TRUE) 435 { 436 return FALSE; 437 } 438 if (find_flag == FALSE) 439 { //不管怎樣先直接插入 440 p->keynum++; 441 for (index = p->keynum;index > temp;--index) 442 { 443 p->key[index] = p->key[index - 1]; 444 p->ptr[index] = p->ptr[index - 1]; 445 } 446 p->ptr[temp] = NULL; 447 p->key[temp] = e.key; 448 if (p->keynum == m) //這種情況得分裂 449 { 450 splitBTree(p); 451 } 452 renewParent(T); 453 return OK; 454 } 455 return ERROR; 456 } 457 /*** 458 * @name Status borrowBNode(BTree &T) 459 * @description 遞迴實現,向兄弟借元素,否則和兄弟合併 460 * @return 成功返回OK,否則返回ERROR 461 * @notice 這種情況應該是T為單元素結點 462 ***/ 463 Status borrowBNode(BTree T) 464 { 465 int mynum, bronum, index; 466 BTree b = NULL, f = NULL; 467 if (T == NULL) return ERROR; 468 f = T->parent; 469 if (f == NULL)//考慮父親結點不存在的情況 470 { 471 if (T->keynum == 0) 472 { 473 f = T->ptr[0]; 474 if (f == NULL) 475 { 476 free(T); 477 return EMPTY; 478 } 479 for (index = 0;index <= f->keynum;index++) 480 { 481 T->key[index] = f->key[index]; 482 T->ptr[index] = f->ptr[index]; 483 } 484 T->keynum = f->keynum; 485 free(f); 486 renewParent(T); 487 } 488 return OK; 489 } 490 mynum = whichSon(T); 491 if (mynum == 0) 492 bronum = 1; 493 else 494 bronum = mynum - 1; 495 b = f->ptr[bronum]; 496 if (b->keynum == (m + 1) / 2 - 1) //如果兄弟幫不了你了 497 { 498 //那麼就和這個兄弟合體 499 if (bronum < mynum) //如果我不是第一個 500 { 501 b->keynum++; 502 b->key[b->keynum] = f->key[mynum]; 503 b->ptr[b->keynum] = T->ptr[0]; 504 for (index = 1