From 357d37b72a14c1221b241e32baf3aa15d0add15a Mon Sep 17 00:00:00 2001 From: e2hang <2099307493@qq.com> Date: Wed, 27 Aug 2025 17:33:56 +0800 Subject: [PATCH] Balance Tree --- BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h | 378 ++++++++++++++++++ BinaryTree/BalanceTree/BPlus-Tree/Node.h | 15 + BinaryTree/BalanceTree/BPlus-Tree/main.cpp | 25 ++ .../BalanceTree/Red-Black Tree/README.MD | 1 + 4 files changed, 419 insertions(+) create mode 100644 BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h create mode 100644 BinaryTree/BalanceTree/BPlus-Tree/Node.h create mode 100644 BinaryTree/BalanceTree/BPlus-Tree/main.cpp diff --git a/BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h b/BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h new file mode 100644 index 0000000..0ec5c9c --- /dev/null +++ b/BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h @@ -0,0 +1,378 @@ +#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]; + } +} diff --git a/BinaryTree/BalanceTree/BPlus-Tree/Node.h b/BinaryTree/BalanceTree/BPlus-Tree/Node.h new file mode 100644 index 0000000..6003868 --- /dev/null +++ b/BinaryTree/BalanceTree/BPlus-Tree/Node.h @@ -0,0 +1,15 @@ +#pragma once +#include +template +class Node { +public: + //使用的时候T可以是pair + std::vector keys; + std::vector*> children; + bool isLeaf; + Node* next; + + Node() = delete; + Node(bool _isLeaf) : isLeaf(_isLeaf), next(nullptr) {} + Node(bool _isLeaf, Node* _next) : isLeaf(_isLeaf), next(_next) {} +}; \ No newline at end of file diff --git a/BinaryTree/BalanceTree/BPlus-Tree/main.cpp b/BinaryTree/BalanceTree/BPlus-Tree/main.cpp new file mode 100644 index 0000000..0d3d5c9 --- /dev/null +++ b/BinaryTree/BalanceTree/BPlus-Tree/main.cpp @@ -0,0 +1,25 @@ +#include "BPlusTree.h" +using namespace std; +int main() { + BPlusTree tree(5); + tree.insert(0); + tree.insert(10); + tree.insert(5); + tree.insert(9); + tree.insert(8); + tree.insert(1); + tree.insert(2); + tree.insert(3); + tree.insert(4); + tree.displayLeaf(); + tree.areaSearch(2, 8); + tree.erase(4); + tree.displayLeaf(); + return 0; +} + +/* +0 1 C 2 3 4 C 5 8 C 9 10 C +2 3 4 5 8 +0 1 C 2 3 C 5 8 C 9 10 C +*/ \ No newline at end of file diff --git a/BinaryTree/BalanceTree/Red-Black Tree/README.MD b/BinaryTree/BalanceTree/Red-Black Tree/README.MD index 412dc7e..2bfa43c 100644 --- a/BinaryTree/BalanceTree/Red-Black Tree/README.MD +++ b/BinaryTree/BalanceTree/Red-Black Tree/README.MD @@ -312,3 +312,4 @@ --- 瑕佷笉瑕佹垜甯綘鎶娾3 绉嶆儏鍐 鈫 杞寲涓 2 绉嶇畝鍗曟儏鍐碘濈殑娴佺▼鐢绘垚涓涓 **鍐崇瓥鍥撅紙鍒犻櫎娴佺▼鍥撅級**锛熻繖鏍蜂細鏇寸洿瑙傘 +