#pragma once #include "Node.h" #include #include template class BPlusTree { private: Node* root; int M; Node* firstLeaf;//做链表范围查找 void splitChild(Node* _node, int _i); void insertNonFull(Node* _node, const T& _key); void erase(Node* _node, const T& _key); //void fixUnderflow(Node* _node);没写 parent T& getMin(Node* _node); void borrowLeft(Node* _node, int _i); void borrowRight(Node* _node, int _i); void mergeLeft(Node* _node, int _i); void mergeRight(Node* _node, int _i); public: BPlusTree() = delete; BPlusTree(int _M) : M(_M) { root = new Node(true); firstLeaf = root; } void insert(const T& _key); Node* search(const T& _key); void areaSearch(const T& _low, const T& _up); void displayLeaf(); void erase(const T& _key); }; template inline void BPlusTree::splitChild(Node* _node, int _i) { Node* child = _node->children[_i]; Node* newc = new Node(_node->children[_i]->isLeaf); //中点,这个就是阶数的计算方式了,之前用t - 1 和 2t - 1 int mid = (M - 1) / 2; //mid前面是左树,从mid开始往后是右树 //拷贝元素 newc->keys.assign(child->keys.begin() + mid, child->keys.end()); child->keys.resize(mid); //拷贝孩子 if (!child->isLeaf) { newc->children.assign(child->children.begin() + mid + 1, child->children.end()); child->children.resize(mid + 1); } //更新next节点 if (child->isLeaf) { newc->next = child->next; child->next = newc; } //比B树多的一步-更新_node,一般都是更新左(最小值) //区别内部外部节点 if (!child->isLeaf) //删掉newc第一个:例子-1,2,3,4,5,分为1,2;3,4,5,这时候推3,要把3从newc的第一个移除 newc->keys.erase(newc->keys.begin()); _node->keys.insert(_node->keys.begin() + _i, newc->keys.front()); _node->children.insert(_node->children.begin() + _i + 1, newc); } template inline void BPlusTree::insertNonFull(Node* _node, const T& _key) { //是叶子节点直接插入 if (_node->isLeaf) { auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key); _node->keys.insert(it, _key); // 插入到第一个 >= _key 的位置 } //不是叶子节点接着递归寻找 else { auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key); int idx = it - _node->keys.begin(); if (_node->children[idx]->keys.size() == M - 1) { splitChild(_node, idx); } //插在哪边 if (_node->keys[idx] < _key) idx++; insertNonFull(_node->children[idx], _key); } } template inline void BPlusTree::erase(Node* _node, const T& _key) { int mid = (M - 1) / 2; if (!search(_key)) return; if (!_node) return; //前一半和search一样 //外部节点 if (_node->isLeaf) { auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key); int idx = it - _node->keys.begin(); if(it != _node->keys.end() && *it == _key) _node->keys.erase(it); //没事直接return if (root == _node || _node->keys.size() >= mid){ return; } } //内部节点 else { auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key); int idx = it - _node->keys.begin(); //若在索引,先替换本值为children[idx]的第二小值 if (it != _node->keys.end() && *it == _key) { *it = getMin(_node->children[idx + 1]); } erase(_node->children[idx], _key); //回溯的时候检查下溢,在这里检查(如果有parent节点就直接设置函数fixunderflow(_node)了) Node* child = _node->children[idx]; if (child->keys.size() < mid) { //先借 // 借左兄弟 if (idx > 0 && _node->children[idx - 1]->keys.size() > mid) { borrowLeft(_node, idx); } // 借右兄弟 else if (idx < _node->children.size() - 1 && _node->children[idx + 1]->keys.size() > mid) { borrowRight(_node, idx); } // 借不到就合并 else if (idx > 0) { mergeLeft(_node, idx); // 和左兄弟合并 } else if (idx < _node->children.size() - 1) { mergeRight(_node, idx); // 和右兄弟合并 } } } } /* template inline void BPlusTree::fixUnderflow(Node* _node) { //先找旁边借 //借不到就合并 }*/ template inline T& BPlusTree::getMin(Node* _node) { if (!_node || _node->keys.empty()) { throw std::runtime_error("Empty node has no minimum key"); } Node* cur = _node; while (!cur->isLeaf) { cur = cur->children[0]; // 重点:最小的,一直往左子树走 } return cur->keys[0]; // 最左叶子的第一个 key } template inline void BPlusTree::borrowLeft(Node* _node, int _i) { // 叶子节点 if (_node->isLeaf) { T tmp = _node->children[_i - 1]->keys.back(); _node->children[_i - 1]->keys.pop_back(); _node->children[_i]->keys.insert(_node->children[_i]->keys.begin(), tmp); _node->keys[_i - 1] = _node->children[_i]->keys[0]; // 更新父节点分界 key } // 内部节点 else { Node* left = _node->children[_i - 1]; Node* cur = _node->children[_i]; // 父节点分界 key 移到当前节点首 cur->keys.insert(cur->keys.begin(), _node->keys[_i - 1]); // 左兄弟最后 key 移到父节点 _node->keys[_i - 1] = left->keys.back(); left->keys.pop_back(); // 左兄弟最后子节点移到当前节点首(带着孩子一起动) Node* c = left->children.back(); left->children.pop_back(); cur->children.insert(cur->children.begin(), c); } } template inline void BPlusTree::borrowRight(Node* _node, int _i) { // 叶子节点 if (_node->isLeaf) { Node* cur = _node->children[_i]; Node* right = _node->children[_i + 1]; // 右兄弟第一个 key 移到当前节点末尾 T tmp = right->keys.front(); right->keys.erase(right->keys.begin()); cur->keys.push_back(tmp); // 更新父节点分界 key _node->keys[_i] = right->keys.front(); } // 内部节点 else { Node* cur = _node->children[_i]; Node* right = _node->children[_i + 1]; // 父节点分界 key 移到当前节点末尾 cur->keys.push_back(_node->keys[_i]); // 右兄弟第一个 key 移到父节点 _node->keys[_i] = right->keys.front(); right->keys.erase(right->keys.begin()); // 右兄弟第一个子节点移到当前节点末尾 Node* c = right->children.front(); right->children.erase(right->children.begin()); cur->children.push_back(c); } } /* template inline void BPlusTree::mergeLeft(Node* _node, int _i) { //处理父节点多出的东西 Node* c = _node->children[_i]; _node->keys.erase(_node->keys.begin() + _i); //合并 _node->children[_i - 1].insert(_node->children[_i - 1].end(), c.begin(), c.end()); _node->children[_i - 1]->children.insert(_node->children[_i - 1]->children.end(), c->children.begin(), c->children.end()); } */ template inline void BPlusTree::mergeLeft(Node* _node, int _i) { Node* left = _node->children[_i - 1]; Node* cur = _node->children[_i]; // 1. 父节点 key 移动 / 删除 if (!left->isLeaf) { // 内部节点:父节点分界 key 移到左兄弟末尾 left->keys.push_back(_node->keys[_i - 1]); } _node->keys.erase(_node->keys.begin() + (_i - 1)); // 2. 合并 keys left->keys.insert(left->keys.end(), cur->keys.begin(), cur->keys.end()); // 3. 合并 children(仅内部节点) if (!left->isLeaf) { left->children.insert(left->children.end(), cur->children.begin(), cur->children.end()); } // 4. 叶子节点更新 next 指针 if (left->isLeaf) { left->next = cur->next; } // 5. 删除父节点 children 中的当前节点 _node->children.erase(_node->children.begin() + _i); } template inline void BPlusTree::mergeRight(Node* _node, int _i) { Node* cur = _node->children[_i]; Node* right = _node->children[_i + 1]; // 1. 父节点 key if (!cur->isLeaf) { // 内部节点:父节点分界 key 移到当前节点末尾 cur->keys.push_back(_node->keys[_i]); } // 2. 合并 keys cur->keys.insert(cur->keys.end(), right->keys.begin(), right->keys.end()); // 3. 合并 children(仅内部节点) if (!cur->isLeaf) { cur->children.insert(cur->children.end(), right->children.begin(), right->children.end()); } // 4. 叶子节点更新 next 指针 if (cur->isLeaf) { cur->next = right->next; } // 5. 删除父节点 key _node->keys.erase(_node->keys.begin() + _i); // 6. 删除父节点 children 中的右兄弟 _node->children.erase(_node->children.begin() + _i + 1); } template inline void BPlusTree::insert(const T& _key) { //分裂根 if (root->keys.size() == M - 1) { Node* newr = new Node(false); newr->children.push_back(root); splitChild(newr, 0); root = newr; } //插入 insertNonFull(root, _key); } template inline Node* BPlusTree::search(const T& _key) { Node* tmp = root; while (tmp) { auto it = std::lower_bound(tmp->keys.begin(), tmp->keys.end(), _key); int idx = it - tmp->keys.begin(); if (tmp->isLeaf) { //判断是否溢出,如果范围搜索需要用到,那么均需要返回tmp,单个索引的时候再根据返回的值搜索一遍即可 return tmp; } else { tmp = tmp->children[idx]; } } return nullptr; } template inline void BPlusTree::areaSearch(const T& _low, const T& _up) { //最好不直接用search,返回的东西不一样 Node* tmp = search(_low); if (!tmp) return; while (tmp) { for (auto x : tmp->keys) { if (x > _up) { std::cout << std::endl; return; } if (x >= _low) std::cout << x << " "; } tmp = tmp->next; } std::cout << std::endl; } template inline void BPlusTree::displayLeaf() { Node* tmp = firstLeaf; while (tmp) { for (auto x : tmp->keys) std::cout << x << " "; tmp = tmp->next; std::cout << "C "; } std::cout << std::endl; } template inline void BPlusTree::erase(const T& _key) { if (!root) return; //递归删除 erase(root, _key); if (root->isLeaf && root->keys.size() == 0) { root = root->children[0]; } }