B树和B+树的解析应用

B树和B+树是两种重要的多路平衡搜索树结构,广泛应用于数据库和文件系统领域。下面我们将从C语言实现的角度深入解析它们的原理和实现细节。

一、B树解析

1. 结构定义

复制代码
#define M 4  // B树的阶数(每个节点最多有M-1个键)

typedef struct BTreeNode {
   
    int keys[M-1];         // 关键字数组
    struct BTreeNode* children[M]; // 子节点指针数组
    int key_num;           // 当前节点关键字数量
    bool is_leaf;          // 是否为叶子节点
} BTree;

2. 核心特性

  • 每个节点最多包含M-1个键,至少⌈M/2⌉-1个键(根节点除外)
  • 所有叶子节点位于同一层次
  • 插入删除操作通过分裂和合并保持平衡

3. 插入操作流程

复制代码
void BTreeInsert(BTree** root, int key) {
   
    BTree* node = *root;
    // 根节点已满时进行分裂
    if (node->key_num == M-1) {
   
        BTree* new_root = createNode();
        new_root->children[0] = node;
        splitChild(new_root, 0);
        *root = new_root;
    }
    insertNonFull(*root, key);
}

4. 节点分裂示例

复制代码
void splitChild(BTree* parent, int index) {
   
    BTree* child = parent->children[index];
    BTree* new_node = createNode();

    // 新节点获取后半部分键
    for (int i = 0; i < M/2-1; i++) {
   
        new_node->keys[i] = child->keys[i + M/2];
    }

    // 中间键提升到父节点
    parent->keys[index] = child->keys[M/2-1];

    // 调整父子关系
    parent->children[index+1] = new_node;
    parent->key_num++;
}

5. 查找算法

复制代码
BTree* BTreeSearch(BTree* node, int key) {
   
    int i = 0;
    while (i < node->key_num && key > node->keys[i])
        i++;

    if (i < node->key_num && key == node->keys[i])
        return node;

    if (node->is_leaf)
        return NULL;

    return BTreeSearch(node->children[i], key);
}

二、B+树解析

1. 结构定义

复制代码
#define M 4  // 阶数

typedef struct BPlusTreeNode {
   
    int keys[M-1];
    union {
   
        struct BPlusTreeNode* children[M]; // 内部节点使用
        struct {
   
            void** data[M];          // 叶子节点数据指针
            struct BPlusTreeNode* next; // 叶子节点链表
        };
    };
    int key_num;
    bool is_leaf;
} BPlusTree;

2. 核心特性

  • 所有数据存储在叶子节点,内部节点仅作索引
  • 叶子节点形成有序双向链表
  • 内部节点的键值等于右子树的最小值

3. 与B树的对比

特征 B树 B+树
数据存储位置 所有节点 仅叶子节点
叶子节点链接 双向链表
查询稳定性 不稳定 稳定
范围查询效率 较低 极高
空间利用率 较低 较高

4. 插入算法特点

复制代码
void BPlusTreeInsert(BPlusTree** root, int key, void* data) {
   
    // 查找插入位置
    BPlusTree* leaf = findLeaf(*root, key);

    // 叶子节点分裂逻辑
    if (leaf->key_num == M-1) {
   
        BPlusTree* new_leaf = splitLeaf(leaf);
        insertIntoParent(root, leaf, new_leaf->keys[0], new_leaf);
    }

    // 插入数据到叶子节点
    insertIntoLeaf(leaf, key, data);
}

5. 范围查询优势

复制代码
void rangeQuery(BPlusTree* root, int start, int end) {
   
    BPlusTree* leaf = findLeaf(root, start);

    while (leaf != NULL) {
   
        for (int i = 0; i < leaf->key_num; i++) {
   
            if (leaf->keys[i] >= start && leaf->keys[i] <= end) {
   
                // 处理数据
                processData(leaf->data[i]);
            }
            if (leaf->keys[i] > end) return;
        }
        leaf = leaf->next;
    }
}

三、性能对比分析

  1. 查询效率

    • B树:最好情况O(1)(在根节点命中)
    • B+树:稳定O(log N),必须到达叶子节点
  2. 空间利用

    • B+树的内部节点更紧凑,相同内存可存储更多索引
  3. 适用场景

    • B树:随机访问较多,查询深度不敏感的场景
    • B+树:范围查询频繁,需要稳定查询性能的系统

四、实现注意事项

  1. 节点设计优化

    复制代码
    // 内存对齐优化
    typedef struct {
         
     int keys[M-1];
     void* pointers[M];
     unsigned char key_num;
     bool is_leaf;
     uint16_t flags; // 用于扩展标记
    } __attribute__((aligned(64))) CacheOptimizedNode;
  2. 并发控制

    复制代码
    // 使用读写锁保护节点
    typedef struct {
         
     pthread_rwlock_t lock;
     BPlusTreeNode* node;
    } ConcurrentNode;
  3. 持久化存储

    复制代码
    // 序列化节点结构
    #pragma pack(push, 1)
    typedef struct {
         
     uint32_t magic_number;
     uint16_t key_count;
     uint8_t  node_type;
     int      keys[M-1];
     uint64_t children[M];
    } DiskNode;
    #pragma pack(pop)
相关推荐
.柒宇.9 小时前
力扣hoT100之找到字符串中所有字母异位词(java版)
java·数据结构·算法·leetcode
Dontla10 小时前
React zustand todos案例(带本地存储localStorage、persist)todoStore.ts
前端·react.js·前端框架
王璐WL11 小时前
【数据结构】单链表的经典算法题
数据结构·算法
Zzzzmo_11 小时前
Java数据结构:二叉树
java·数据结构·算法
聆风吟º12 小时前
【数据结构入门手札】数据结构基础:从数据到抽象数据类型
数据结构·数据类型·逻辑结构·数据对象·物理结构·数据项·数据元素
啊吧怪不啊吧12 小时前
二分查找算法介绍及使用
数据结构·算法·leetcode
立志成为大牛的小牛14 小时前
数据结构——四十二、二叉排序树(王道408)
数据结构·笔记·程序人生·考研·算法
im_AMBER18 小时前
Vite + React 项目启动深度踩坑指南
前端·学习·react.js·前端框架
Hammer Ray18 小时前
前端开发基础概念(React)
前端·react.js·前端框架
摇滚侠21 小时前
StreamAPI,取出list中的name属性,返回一个新list
数据结构·list