c++实现B+树

88 阅读2分钟

以下是带有分裂和合并操作的B+树实现,包括了分裂和合并节点的过程:

#include <iostream>
#include <vector>
#include <algorithm>

// B+树节点
template<typename KeyType, typename ValueType>
class BPlusTreeNode {
public:
    bool leaf; // 是否为叶子节点
    std::vector<KeyType> keys; // 键值列表
    std::vector<ValueType> values; // 值列表
    BPlusTreeNode<KeyType, ValueType>* parent; // 父节点
    std::vector<BPlusTreeNode<KeyType, ValueType>*> children; // 子节点列表

    // 构造函数
    BPlusTreeNode(bool _leaf) : leaf(_leaf), parent(nullptr) {}

    // 在节点中查找键值
    int findKey(const KeyType& key) {
        auto it = std::lower_bound(keys.begin(), keys.end(), key);
        return std::distance(keys.begin(), it);
    }

    // 插入键值
    void insert(const KeyType& key, const ValueType& value) {
        auto it = std::lower_bound(keys.begin(), keys.end(), key);
        int idx = std::distance(keys.begin(), it);
        keys.insert(it, key);
        values.insert(values.begin() + idx, value);
    }

    // 分裂节点
    void split(BPlusTreeNode<KeyType, ValueType>*& newParent) {
        // 创建新的右节点
        BPlusTreeNode<KeyType, ValueType>* rightNode = new BPlusTreeNode<KeyType, ValueType>(leaf);
        int midIdx = keys.size() / 2;
        rightNode->keys.assign(keys.begin() + midIdx, keys.end());
        rightNode->values.assign(values.begin() + midIdx, values.end());
        if (!leaf) {
            rightNode->children.assign(children.begin() + midIdx, children.end());
            for (auto& child : rightNode->children) {
                child->parent = rightNode;
            }
            children.erase(children.begin() + midIdx, children.end());
        }
        keys.resize(midIdx);
        values.resize(midIdx);

        // 插入新节点到父节点中
        int insertIdx = parent->findKey(keys[0]);
        parent->insert(keys[midIdx], values[midIdx]);
        parent->children.insert(parent->children.begin() + insertIdx + 1, rightNode);
        rightNode->parent = parent;

        // 如果父节点的键值个数超过阈值,则继续分裂父节点
        if (parent->keys.size() > maxKeys) {
            parent->split(newParent);
        } else {
            newParent = parent;
        }
    }

    // 合并节点
    void merge(BPlusTreeNode<KeyType, ValueType>*& newParent) {
        // 找到当前节点在父节点中的位置
        int parentIdx = parent->findKey(keys[0]);
        BPlusTreeNode<KeyType, ValueType>* sibling = nullptr;
        // 如果当前节点不是父节点的第一个子节点,那么合并它和左兄弟
        if (parentIdx > 0) {
            sibling = parent->children[parentIdx - 1];
        }
        // 否则合并它和右兄弟
        else {
            sibling = parent->children[parentIdx + 1];
        }

        // 将父节点的键值和子节点合并到当前节点
        keys.push_back(parent->keys[parentIdx]);
        keys.insert(keys.end(), sibling->keys.begin(), sibling->keys.end());
        values.insert(values.end(), sibling->values.begin(), sibling->values.end());
        children.insert(children.end(), sibling->children.begin(), sibling->children.end());

        // 删除父节点的键值和子节点
        parent->keys.erase(parent->keys.begin() + parentIdx);
        parent->children.erase(parent->children.begin() + parentIdx + 1);

        // 如果父节点的键值个数小于最小键值个数,继续合并父节点
        if (parent->keys.size() < minKeys) {
            parent->merge(newParent);
        } else {
            newParent = parent;
        }
    }

private:
    static constexpr int maxKeys = 3; // 节点的最大键值个数
    static constexpr int minKeys = maxKeys / 2; // 节点的最小键值个数
};

// B+树
template<typename KeyType, typename ValueType>
class BPlusTree {
public:
    BPlusTree() : root(nullptr) {}

    // 查找键值
    bool search(const KeyType& key) {
        return root ? root->search(key) : false;
    }

    // 插入键值
    void insert(const KeyType& key, const ValueType& value) {
        if (!root) {
            root = new BPlusTreeNode<KeyType, ValueType>(true);
            root->insert(key, value);
        } else {
            BPlusTreeNode<KeyType, ValueType>* node = findLeafNode(key);
            node->insert(key, value);
            if (node->keys.size() > node->maxKeys) {
                BPlusTreeNode<KeyType, ValueType>* newParent = nullptr;
                node->split(newParent);
                if (newParent) {
                    root = newParent;
                }
            }
        }
    }

private:
    BPlusTreeNode<KeyType, ValueType>* root;

    // 查找叶子节点
    BPlusTreeNode<KeyType, ValueType>* findLeafNode(const KeyType& key) {
        BPlusTreeNode<KeyType, ValueType>* curr = root;
        while (!curr->leaf) {
            int idx = curr->findKey(key);
            curr = curr->children[idx];
        }
        return curr;
    }
};

int main() {
    BPlusTree<int, std::string> tree;
    tree.insert(10, "Value 1");
    tree.insert(20, "Value 2");
    tree.insert(5, "Value 3");
    tree.insert(15, "Value 4");
    tree.insert(25, "Value 5");
    tree.insert(12, "Value 6");
    tree.insert(18, "Value 7");
    tree.insert(22, "Value 8");

    std::cout << "Search for key 20: " << (tree.search(20) ? "Found" : "Not found") << std::endl;
    std::cout << "Search for key 7: " << (tree.search(7) ? "Found" : "Not found") << std::endl;

    return 0;
}