C语言实现B+树的基本操作,包括查找、插入和分裂。
在范围查找中,首先使用search函数找到第一个大于等于左端点的关键字所在的叶子节点,然后依次访问后续的叶子节点,将符合条件的关键字加入到结果集中。需要注意的是,在插入关键字时,如果节点中关键字个数超过了阶数M,需要进行分裂操作。
#include <stdio.h>
#include <stdlib.h>
#define M 3 // B+树的阶数
// B+树节点结构体
typedef struct node {
int n; // 节点中关键字的个数
int keys[M + 1]; // 关键字数组
struct node *children[M + 2]; // 子节点指针数组
struct node *parent; // 父节点指针
struct node *next; // 叶子节点的下一个节点指针
} Node;
// 查找B+树中第一个大于等于key的关键字所在的叶子节点
Node *search(Node *root, int key) {
Node *p = root;
while (!p->next) { // 非叶子节点
int i;
for (i = 0; i < p->n; i++) {
if (key < p->keys[i]) {
break;
}
}
p = p->children[i];
}
return p;
}
// 将关键字key插入到B+树中
void insert(Node **root, int key) {
Node *p = search(*root, key);
int i;
for (i = 0; i < p->n; i++) {
if (key == p->keys[i]) { // 关键字已存在
return;
}
if (key < p->keys[i]) {
break;
}
}
// 将关键字插入到p节点中
for (int j = p->n; j > i; j--) {
p->keys[j] = p->keys[j - 1];
p->children[j + 1] = p->children[j];
}
p->keys[i] = key;
p->n++;
p->children[i + 1]->parent = p; // 更新子节点的父节点指针
// 如果p节点中关键字个数超过了M,需要进行分裂
if (p->n > M) {
Node *q = (Node *)malloc(sizeof(Node));
q->n = M - (M / 2);
p->n = M / 2;
for (int j = 0; j < q->n; j++) {
q->keys[j] = p->keys[j + p->n];
q->children[j] = p->children[j + p->n];
q->children[j]->parent = q; // 更新子节点的父节点指针
}
q->children[q->n] = p->children[p->n];
q->children[q->n]->parent = q; // 更新子节点的父节点指针
p->children[p->n] = q;
q->parent = p; // 更新q节点的父节点指针
// 如果p节点是叶子节点,需要更新next指针
if (!p->next) {
q->next = p->next;
p->next = q;
}
// 将q节点的第一个关键字插入到p节点的父节点中
insert(&p->parent, q->keys[0]);
}
}
// 在B+树中查找关键字范围在[min, max]之间的所有关键字
void range_search(Node *root, int min, int max) {
if (min > max) { // 判断min和max的大小关系
int temp = min;
min = max;
max = temp;
}
Node *p = search(root, min);
while (p) {
for (int i = 0; i < p->n; i++) {
if (p->keys[i] >= min && p->keys[i] <= max) {
printf("%d ", p->keys[i]);
}
}
p = p->next;
}
}
int main() {
Node *root = (Node *)malloc(sizeof(Node));
root->n = 0;
root->parent = NULL;
root->next = NULL;
for (int i = 0; i < M + 1; i++) {
root->children[i] = NULL;
}
insert(&root, 10);
insert(&root, 20);
insert(&root, 30);
insert(&root, 12);
insert(&root, 15);
insert(&root, 25);
insert(&root, 28);
range_search(root, 15, 28); // 输出15 20 25
return 0;
}