void test_BTree_remove(BTree* tree, int key) { printf("\n移除关键字 %c \n", key); BTree_remove(tree, key); BTree_print(*tree); printf("\n"); }
void BTree_remove(BTree* tree, int key) { // B-数的保持条件之一: // 非根节点的内部节点的关键字数目不能少于 BTree_T - 1 int i, j, index; BTNode *root = *tree; BTNode *node = root; BTNode *prevChild, *nextChild, *child; int prevKey, nextKey; if (!root) { printf("Failed to remove %c, it is not in the tree!\n", key); return; } index = 0; while (index < node->keynum && key > node->key[index]) { ++index; } // // index of key: i-1 i i+1 // +---+---+---+---+---+ // ... + + A + + ... // +---+---+---+---+---+ // / | \ // index of C: i - 1 i i + 1 // / | \ // +---+---+ +---+ +---+---+ // ... + + + + + + ... // +---+---+ +---+ +---+---+ // prevChild child nextChild // Find the key. if (index < node->keynum && node->key[index] == key) { // 1,所在节点是叶子节点,直接删除 if (node->isLeaf) { for (i = index; i < node->keynum; ++i) { node->key[i] = node->key[i + 1]; node->child[i + 1] = node->child[i + 2]; } --node->keynum; if (node->keynum == 0) { assert(node == *tree); free(node); *tree = NULL; } return; } // 2a,如果位于 key 前的子节点的 key 数目 >= BTree_T, // 在其中找 key 的前驱,用前驱的 key 值赋予 key, // 然后在前驱所在孩子节点中递归删除前驱。 else if (node->child[index]->keynum >= BTree_T) { prevChild = node->child[index]; prevKey = prevChild->key[prevChild->keynum - 1]; node->key[index] = prevKey; BTree_remove(&prevChild, prevKey); } // 2b,如果位于 key 后的子节点的 key 数目 >= BTree_T, // 在其中找 key 的后继,用后继的 key 值赋予 key, // 然后在后继所在孩子节点中递归删除后继。 else if (node->child[index + 1]->keynum >= BTree_T) { nextChild = node->child[index + 1]; nextKey = nextChild->key[0]; node->key[index] = nextKey; BTree_remove(&nextChild, nextKey); } // 2c,前驱和后继都只包含 BTree_T - 1 个节点, // 将 key 下降前驱孩子节点,并将后继孩子节点合并到前驱孩子节点, // 删除后继孩子节点,在 node 中移除 key 和指向后继孩子节点的指针, // 然后在前驱所在孩子节点中递归删除 key。 else if (node->child[index]->keynum == BTree_T - 1 && node->child[index + 1]->keynum == BTree_T - 1){ prevChild = node->child[index]; BTree_merge_child(tree, node, index); // 在前驱孩子节点中递归删除 key BTree_remove(&prevChild, key); } } // 3,key 不在内节点 node 中,则应当在某个包含 key 的子节点中。 // key < node->key[index], 所以 key 应当在孩子节点 node->child[index] 中 else { child = node->child[index]; if (!child) { printf("Failed to remove %c, it is not in the tree!\n", key); return; } if (child->keynum == BTree_T - 1) { prevChild = NULL; nextChild = NULL; if (index - 1 >= 0) { prevChild = node->child[index - 1]; } if (index + 1 <= node->keynum) { nextChild = node->child[index + 1]; } // 3a,如果所在孩子节点相邻的兄弟节点中有节点至少包含 BTree_t 个关键字 // 将 node 的一个关键字下降到 child 中,将相邻兄弟节点中一个节点上升到 // node 中,然后在 child 孩子节点中递归删除 key。 if ((prevChild && prevChild->keynum >= BTree_T) || (nextChild && nextChild->keynum >= BTree_T)) { if (nextChild && nextChild->keynum >= BTree_T) { child->key[child->keynum] = node->key[index]; child->child[child->keynum + 1] = nextChild->child[0]; ++child->keynum; node->key[index] = nextChild->key[0]; for (j = 0; j < nextChild->keynum - 1; ++j) { nextChild->key[j] = nextChild->key[j + 1]; nextChild->child[j] = nextChild->child[j + 1]; } --nextChild->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] = prevChild->child[prevChild->keynum]; child->key[0] = node->key[index - 1]; ++child->keynum; node->key[index - 1] = prevChild->key[prevChild->keynum - 1]; --prevChild->keynum; } } // 3b, 如果所在孩子节点相邻的兄弟节点都只包含 BTree_t - 1 个关键字, // 将 child 与其一相邻节点合并,并将 node 中的一个关键字下降到合并节点中, // 再在 node 中删除那个关键字和相关指针,若 node 的 key 为空,删之,并调整根。 // 最后,在相关孩子节点中递归删除 key。 else if ((!prevChild || (prevChild && prevChild->keynum == BTree_T - 1)) && ((!nextChild || nextChild && nextChild->keynum == BTree_T - 1))) { if (prevChild && prevChild->keynum == BTree_T - 1) { BTree_merge_child(tree, node, index - 1); child = prevChild; } else if (nextChild && nextChild->keynum == BTree_T - 1) { BTree_merge_child(tree, node, index); } } } BTree_remove(&child, key); } }