基本的 B 树和 B+ 树操作的代码

假设 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);
}

 

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值