B+树是一种自平衡的树数据结构,广泛应用于数据库和文件系统中,用于高效地存储和检索数据。B+树的特点是每个节点可以拥有多个子节点,并且所有值都保存在叶子节点中,而内部节点只作为导航指针。以下是对 B+ 树实现的详细介绍。
B+ 树的基本特征
- 阶(Order):B+树的阶定义为一个节点最多可以包含多少个子指针(或键值)。通常用 - m表示。
- 性质: - 每个内部节点最多有 m个子指针,最少有 ⌈m/2⌉ 个子指针(除根节点外)。
- 所有叶子节点在同一层,并且按顺序相连,以便能高效进行范围查询。
- 内部节点只存储键值,不直接存储数据。
- 只有叶子节点保存实际的数据记录或数据的指针。
 
- 每个内部节点最多有 
- 高度平衡:由于每次插入或删除操作可能会导致树的不平衡,B+树通过分裂和合并操作保持其高度平衡,使得任何时候从根到叶子的路径长度是相同的。 
B+ 树的基本操作
1. 插入操作
- 从根开始,寻找合适的位置来插入新的键值。
- 如果找到的是一个内部节点,则根据当前键与该键值进行比较并选择合适的子树继续向下搜索。
- 当到达叶子节点时,将新键插入。如果该叶子节点已经满了(即已包含 m−1 个键),则需要进行分裂:
- 将该叶子的元素一部分移至新的叶子结点,并将新生成的叶子结点的第一个键上升至父亲结点。
 
2. 删除操作
- 查找要删除的键,通过遍历从根到对应叶子的路径找到目标。
- 从叶子中删除该项,如果删除后该叶子不足最小度数 (⌈m/2⌉),则需执行以下步骤之一:
- 从相邻兄弟借用一个元素;
- 或者与兄弟进行合并,形成一个更大的祖先;
 
这样,可能导致祖先也不满足属性,从而需要逐步向上检查并维护 B+ 树特性。
3. 搜索操作
- 搜索过程类似于二叉搜索树,但使用内部节点仅作为导航器,不直接返回结果。在内部节点上查找以确定应访问哪个子树,然后在对应的叶子中查找实际的数据项。
B+ 树示例代码
下面是一个简化版 B+ 树实现的大概轮廓:
#include <iostream>
#include <vector>
const int MAX_KEYS = 4; // 阶数设为4
class Node {
public:
    bool isLeaf;
    std::vector<int> keys; // 存储关键字
    std::vector<Node*> children; // 存储孩子指针
    
    Node(bool leaf) : isLeaf(leaf) {}
};
class BPlusTree {
private:
    Node* root;
    void insertNonFull(Node* node, int key) {
        // 在非满节中插入
        if (node->isLeaf) {
            // 找到插入位置
            auto it = std::lower_bound(node->keys.begin(), node->keys.end(), key);
            node->keys.insert(it, key);
        } else {
            auto it = std::lower_bound(node->keys.begin(), node->keys.end(), key);
            int index = it - node->keys.begin();
            
            if (node->children[index]->keys.size() == MAX_KEYS - 1) { 
                splitChild(node, index); 
                if (key > node->keys[index]) 
                    index++;
            }
            
            insertNonFull(node->children[index], key);
        }
    }
    void splitChild(Node* parent, int index) {
        // 分割孩子
        Node* fullNode = parent->children[index];
        Node* newNode = new Node(fullNode->isLeaf);
        
        for (int i = MAX_KEYS / 2; i < fullNode->keys.size(); ++i)
            newNode->keys.push_back(fullNode->keys[i]);
        
        fullNode->keys.resize(MAX_KEYS / 2);
        
        if (!fullNode->isLeaf) {
            for (int i = MAX_KEYS / 2 + 1; i <= fullNode->children.size(); ++i)
                newNode->children.push_back(fullNode->children[i]);
            
            fullNode->children.resize(MAX_KEYS / 2 + 1);
        }
        
        parent->children.insert(parent->children.begin() + index + 1, newNode);
        parent->keys.insert(parent->keys.begin() + index, fullNode->keys[MAX_KEYS / 2]);
    }
public:
    BPlusTree() : root(nullptr) {}
    void insert(int key) {
        if (!root) {
            root = new Node(true);
            root->keys.push_back(key); // 若树为空,则创建根结点
        } else if (root && root -> keys.size() == MAX_KEYS - 1) { 
           Node *newRoot= new Node(false); 
           newRoot -> children.push_back(root); 
           splitChild(newRoot,0); 
           int idx=0; 
           if(newRoot -> keys[0] <key) idx++; 
           insertNonFull(newRoot -> children[idx],key); 
           root=newRoot;  
       } else {    
             insertNonFull(root,key);    
         }  
     }
     void traverse() { /* 中序遍历方法 */ }
};
// 示例代码使用
int main() {
    BPlusTree bpt;
    bpt.insert(10);
    bpt.insert(20);
    bpt.insert(5);
    return 0;
}
总结
B+树提供了快速查找、插入和删除等操作,并且由于其结构特性,在磁盘存取方面表现优越,非常适合用于数据库索引。通过合理管理分支和填充程度,它能够保证良好的性能,是一种非常实用的数据结构。
内容由零声教学AI助手提供,问题来源于学员提问


 
                             
         
        
 
         
         
         
         
         
         
         
        
 
                 
                 
                 
                 
                 
                 
                 
                