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;
}

posted @ 2024-05-06 14:27  Jikefan  阅读(80)  评论(0)    收藏  举报