B树的构建C语言实现
B树是文件系统的基石,也是数据库的基石。学会B树才能更好的学习B+树。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int level; // 树的阶
int keyNum; // 关键字数量
int* keys; // 关键字数组
int childNum; // 孩子数量
struct Node** children; // 孩子数组
struct Node* parent; // 父亲指针
} Node;
Node* initNode(int level) {
Node* node = (Node*) malloc(sizeof(Node));
node->level = level;
node->keyNum = 0;
node->childNum = 0;
// (null) (level - 1) (放新添加的位) == level + 1
node->keys = (int*) calloc(level + 1, sizeof(int));
node->children = (Node**) calloc(level, sizeof(Node*));
node->parent = NULL;
int i = 0;
for (; i< level; i++) {
node->children[i] = NULL;
node->keys[i] = 0;
}
node->keys[i] = 0;
return node;
}
/**
* 在结点处找到合适的插入索引
* @param node
* @param data
* @return
*/
int findSuitIndex(Node* node, int data) {
int index = 1;
for (; index <= node->keyNum; ++index) {
if (data < node->keys[index]) {
break;
}
}
// 循环跳出时, index会再加一次, 所以会是第一次大于data的索引
return index;
}
/**
* 找到合适插入的叶子结点
* @param T
* @param data
* @return
*/
Node* findSuitLeafNode(Node* T, int data) {
if (T->childNum == 0) {
return T;
}
int index = findSuitIndex(T, data);
return findSuitLeafNode(T->children[index - 1], data);
}
void addData(Node* node, int data, Node** T) {
int index = findSuitIndex(node, data);
for (int i = node->keyNum; index <= i; i--) {
node->keys[i + 1] = node->keys[i];
}
node->keys[index] = data;
node->keyNum++;
// 判断是否需要分裂
if (node->keyNum == node->level) {
// mid = ceil(node->level), 向上取整
int mid = node->level / 2 + (node->level & 1);
Node* lChild = initNode(node->level);
Node* rChild = initNode(node->level);
// 将值赋给子结点
for (int i = 1; i < mid; i++) {
addData(lChild, node->keys[i], T);
}
for (int i = mid + 1; i < node->level + 1; i++) {
addData(rChild, node->keys[i], T);
}
for (int i = 0; i < mid; i++) {
lChild->children[i] = node->children[i];
if (lChild->children[i] != NULL) {
lChild->children[i]->parent = lChild;
lChild->childNum++;
}
}
int rIndex = 0;
for (int i = mid; i < node->childNum; i++) {
rChild->children[rIndex++] = node->children[i];
if (rChild->children[i] != NULL) {
rChild->children[i]->parent = rChild;
rChild->childNum++;
}
}
// 处理父结点
if (node->parent == NULL) {
Node* newParent = initNode(node->level);
newParent->children[0] = lChild;
newParent->children[1] = rChild;
newParent->childNum = 2;
lChild->parent = newParent;
rChild->parent = newParent;
addData(newParent, node->keys[mid], T);
*T = newParent;
free(node);
} else {
int pIndex = findSuitIndex(node->parent, node->keys[mid]);
node->parent->children[pIndex - 1] = lChild;
if (node->parent->children[pIndex] != NULL) {
for (int i = node->parent->childNum - 1; i >= pIndex; i--) {
node->parent->children[i + 1] = node->parent->children[i];
}
}
node->parent->children[pIndex] = rChild;
node->parent->childNum++;
lChild->parent = node->parent;
rChild->parent = node->parent;
addData(node->parent, node->keys[mid], T);
free(node);
}
}
}
void insert(Node** T, int data) {
Node* node = findSuitLeafNode(*T, data);
addData(node, data, T);
}
void printTree(Node* T) {
if (T != NULL) {
for (int i = 1; i <= T->keyNum; i++) {
printf("%d, ", T->keys[i]);
}
printf("\n");
for (int i = 0; i < T->childNum; i++) {
printTree(T->children[i]);
}
}
}
int main() {
printf("Hello, BTree!\n");
Node* T = initNode(5);
for (int i = 1; i <= 15; i++) {
insert(&T, i);
}
printTree(T);
return 0;
}