假设 B 树节点的最大键数为 M,而 B+ 树节点的最大键数为 N(N >= M)。
// B 树节点结构
typedef struct BTreeNode {
int is_leaf; // 是否为叶子节点
int num_keys; // 当前节点存储的键的数量
int keys[M-1]; // 存储的键数组
struct BTreeNode *children[M]; // 子节点指针数组
} BTreeNode;
// B+ 树节点结构
typedef struct BPlusTreeNode {
int is_leaf; // 是否为叶子节点
int num_keys; // 当前节点存储的键的数量
int keys[N-1]; // 存储的键数组
struct BPlusTreeNode *children[N]; // 子节点指针数组
struct BPlusTreeNode *next_leaf; // 指向下一个叶子节点的指针
} BPlusTreeNode;
// 在 B 树中插入键值
void insert_B_tree(BTreeNode *root, int key) {
if (root->num_keys == M-1) {
// 根节点已满,需要拆分
BTreeNode *new_root = malloc(sizeof(BTreeNode));
new_root->is_leaf = 0;
new_root->num_keys = 0;
new_root->children[0] = root;
split_child(new_root, 0);
insert_nonfull(new_root, key);
} else {
insert_nonfull(root, key);
}
}
// 在 B+ 树中插入关键字
void insert_BPlus_tree(BPlusTreeNode **root, int key) {
if (*root == NULL) {
// 树为空,创建新的根节点
BPlusTreeNode *new_root = malloc(sizeof(BPlusTreeNode));
new_root->is_leaf = 1;
new_root->num_keys = 1;
new_root->keys[0] = key;
new_root->children[0] = NULL;
new_root->next_leaf = NULL;
*root = new_root;
} else {
// 找到待插入叶子节点
BPlusTreeNode *leaf = find_leaf(*root, key);
if (leaf->num_keys < N-1) {
// 叶子节点未满,直接插入
insert_to_leaf(leaf, key);
} else {
// 叶子节点已满,需要拆分
BPlusTreeNode *new_leaf = split_leaf(leaf);
insert_to_leaf_after_split(root, leaf, new_leaf, key);
}
}
}
// 查找键在 B 树中的位置
BTreeNode* search_B_tree(BTreeNode *node, int key) {
int i = 0;
while (i < node->num_keys && key > node->keys[i]) {
i++;
}
if (i < node->num_keys && key == node->keys[i]) {
return node; // 找到了
} else if (node->is_leaf) {
return NULL; // 到达叶子节点仍未找到
} else {
return search_B_tree(node->children[i], key); // 递归查找子节点
}
}
// 查找键在 B+ 树中的位置
BPlusTreeNode* search_BPlus_tree(BPlusTreeNode *node, int key) {
if (node == NULL) {
return NULL; // 树为空,未找到
}
int i = 0;
while (i < node->num_keys && key > node->keys[i]) {
i++;
}
if (i < node->num_keys && key == node->keys[i]) {
return node; // 找到了
} else if (node->is_leaf) {
return NULL; // 到达叶子节点仍未找到
} else {
return search_BPlus_tree(node->children[i], key); // 递归查找子节点
}
}
// 将键插入非满节点
void insert_nonfull(BTreeNode *node, int key) {
int i = node->num_keys - 1;
if (node->is_leaf) {
// 节点为叶子节点,直接将键插入合适位置
while (i >= 0 && key < node->keys[i]) {
node->keys[i + 1] = node->keys[i];
i--;
}
node->keys[i + 1] = key;
node->num_keys++;
} else {
// 节点为内部节点,递归向下插入合适位置
while (i >= 0 && key < node->keys[i]) {
i--;
}
i++;
if (node->children[i]->num_keys == M-1) {
// 子节点已满,需要拆分
split_child(node, i);
if (key > node->keys[i]) {
i++;
}
}
insert_nonfull(node->children[i], key);
}
}
// 将键插入叶子节点
void insert_to_leaf(BPlusTreeNode *leaf, int key) {
int i = leaf->num_keys - 1;
while (i >= 0 && key < leaf->keys[i]) {
leaf->keys[i + 1] = leaf->keys[i];
i--;
}
leaf->keys[i + 1] = key;
leaf->num_keys++;
}
// 拆分 B 树节点的子节点
void split_child(BTreeNode *parent, int index) {
BTreeNode *child = parent->children[index];
// 创建新的节点用于存储分裂出的键和子节点
BTreeNode *new_node = malloc(sizeof(BTreeNode));
new_node->is_leaf = child->is_leaf;
new_node->num_keys = M / 2 - 1;
for (int i = 0; i < M / 2 - 1; i++) {
new_node->keys[i] = child->keys[i + M / 2];
}
if (!child->is_leaf) {
for (int i = 0; i < M / 2; i++) {
new_node->children[i] = child->children[i + M / 2];
}
}
child->num_keys = M / 2 - 1;
// 将父节点中的键和子节点后移一位
for (int i = parent->num_keys; i > index; i--) {
parent->keys[i] = parent->keys[i - 1];
parent->children[i + 1] = parent->children[i];
}
parent->keys[index] = child->keys[M / 2 - 1];
parent->children[index + 1] = new_node;
parent->num_keys++;
}
// 拆分叶子节点
BPlusTreeNode* split_leaf(BPlusTreeNode *leaf) {
BPlusTreeNode *new_leaf = malloc(sizeof(BPlusTreeNode));
new_leaf->is_leaf = 1;
// 计算要将键和子节点拆分到新叶子节点的位置
int mid_point = (leaf->num_keys + 1) / 2;
int num_keys_new_leaf = leaf->num_keys - mid_point;
// 将键拆分到新叶子节点
for (int i = 0; i < num_keys_new_leaf; i++) {
new_leaf->keys[i] = leaf->keys[mid_point + i];
}
// 更新叶子节点的键的数量
leaf->num_keys = mid_point;
new_leaf->num_keys = num_keys_new_leaf;
// 更新链表指针
new_leaf->next_leaf = leaf->next_leaf;
leaf->next_leaf = new_leaf;
return new_leaf;
}
// 在拆分后的叶子节点中插入键
void insert_to_leaf_after_split(BPlusTreeNode **root, BPlusTreeNode *leaf, BPlusTreeNode *new_leaf, int key) {
if (leaf == *root) {
// 如果拆分的叶子节点为根节点,需要创建新的根节点
BPlusTreeNode *new_root = malloc(sizeof(BPlusTreeNode));
new_root->is_leaf = 0;
new_root->num_keys = 1;
new_root->keys[0] = new_leaf->keys[0];
new_root->children[0] = leaf;
new_root->children[1] = new_leaf;
new_root->next_leaf = NULL;
*root = new_root;
} else {
// 在父节点中插入拆分出的键和子节点指针
BPlusTreeNode *parent = find_parent(*root, leaf);
int i = parent->num_keys - 1;
while (i >= 0 && leaf != parent->children[i]) {
// 寻找拆分节点在父节点中的位置
parent->keys[i + 1] = parent->keys[i];
parent->children[i + 2] = parent->children[i + 1];
i--;
}
parent->keys[i + 1] = new_leaf->keys[0];
parent->children[i + 2] = new_leaf;
parent->num_keys++;
}
insert_to_leaf(new_leaf, key);
}