Balance Tree

This commit is contained in:
e2hang
2025-08-27 17:33:56 +08:00
parent 96738dec6c
commit 357d37b72a
4 changed files with 419 additions and 0 deletions

View File

@@ -0,0 +1,378 @@
#pragma once
#include "Node.h"
#include <iostream>
#include <algorithm>
template <class T>
class BPlusTree {
private:
Node<T>* root;
int M;
Node<T>* firstLeaf;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD><EFBFBD>
void splitChild(Node<T>* _node, int _i);
void insertNonFull(Node<T>* _node, const T& _key);
void erase(Node<T>* _node, const T& _key);
//void fixUnderflow(Node<T>* _node);ûд parent
T& getMin(Node<T>* _node);
void borrowLeft(Node<T>* _node, int _i);
void borrowRight(Node<T>* _node, int _i);
void mergeLeft(Node<T>* _node, int _i);
void mergeRight(Node<T>* _node, int _i);
public:
BPlusTree() = delete;
BPlusTree(int _M) : M(_M) {
root = new Node<T>(true);
firstLeaf = root;
}
void insert(const T& _key);
Node<T>* search(const T& _key);
void areaSearch(const T& _low, const T& _up);
void displayLeaf();
void erase(const T& _key);
};
template<class T>
inline void BPlusTree<T>::splitChild(Node<T>* _node, int _i)
{
Node<T>* child = _node->children[_i];
Node<T>* newc = new Node<T>(_node->children[_i]->isLeaf);
//<2F>е<D0B5><E3A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC>ʽ<E3B7BD>ˣ<EFBFBD>֮ǰ<D6AE><C7B0>t - 1 <20><> 2t - 1
int mid = (M - 1) / 2;
//midǰ<64><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>mid<69><64>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//<2F><><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA>
newc->keys.assign(child->keys.begin() + mid, child->keys.end());
child->keys.resize(mid);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!child->isLeaf) {
newc->children.assign(child->children.begin() + mid + 1, child->children.end());
child->children.resize(mid + 1);
}
//<2F><><EFBFBD><EFBFBD>next<78>ڵ<EFBFBD>
if (child->isLeaf) {
newc->next = child->next;
child->next = newc;
}
//<2F><>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>-<2D><><EFBFBD><EFBFBD>_node<64><65>һ<EFBFBD><EFBFBD>Ǹ<EFBFBD><C7B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Сֵ<D0A1><D6B5>
//<2F><><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2>ⲿ<EFBFBD>ڵ<EFBFBD>
if (!child->isLeaf)
//ɾ<><C9BE>newc<77><63>һ<EFBFBD><D2BB>:<3A><><EFBFBD><EFBFBD>-1,2,3,4,5<><35><EFBFBD><EFBFBD>Ϊ1,2;3,4,5<><35><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>3<EFBFBD><33>Ҫ<EFBFBD><D2AA>3<EFBFBD><33>newc<77>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ƴ<EFBFBD>
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<class T>
inline void BPlusTree<T>::insertNonFull(Node<T>* _node, const T& _key)
{
//<2F><>Ҷ<EFBFBD>ӽڵ<D3BD>ֱ<EFBFBD>Ӳ<EFBFBD><D3B2><EFBFBD>
if (_node->isLeaf) {
auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key);
_node->keys.insert(it, _key); // <20><><EFBFBD><EFBFBD><EBB5BD>һ<EFBFBD><D2BB> >= _key <20><>λ<EFBFBD><CEBB>
}
//<2F><><EFBFBD><EFBFBD>Ҷ<EFBFBD>ӽڵ<D3BD><DAB5><EFBFBD><EFBFBD>ŵݹ<C5B5>Ѱ<EFBFBD><D1B0>
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);
}
//<2F><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>
if (_node->keys[idx] < _key) idx++;
insertNonFull(_node->children[idx], _key);
}
}
template<class T>
inline void BPlusTree<T>::erase(Node<T>* _node, const T& _key)
{
int mid = (M - 1) / 2;
if (!search(_key)) return;
if (!_node) return;
//ǰһ<C7B0><D2BB><EFBFBD><EFBFBD>searchһ<68><D2BB>
//<2F>ⲿ<EFBFBD>ڵ<EFBFBD>
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);
//û<><C3BB>ֱ<EFBFBD><D6B1>return
if (root == _node || _node->keys.size() >= mid){
return;
}
}
//<2F>ڲ<EFBFBD><DAB2>ڵ<EFBFBD>
else {
auto it = std::lower_bound(_node->keys.begin(), _node->keys.end(), _key);
int idx = it - _node->keys.begin();
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BBBB>ֵΪchildren[idx]<5D>ĵڶ<C4B5>Сֵ
if (it != _node->keys.end() && *it == _key) {
*it = getMin(_node->children[idx + 1]);
}
erase(_node->children[idx], _key);
//<2F><><EFBFBD>ݵ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E9A3A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>parent<6E>ڵ<EFBFBD><DAB5><EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>fixunderflow(_node)<29>ˣ<EFBFBD>
Node<T>* child = _node->children[idx];
if (child->keys.size() < mid) {
//<2F>Ƚ<EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>
if (idx > 0 && _node->children[idx - 1]->keys.size() > mid) {
borrowLeft(_node, idx);
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>
else if (idx < _node->children.size() - 1 && _node->children[idx + 1]->keys.size() > mid) {
borrowRight(_node, idx);
}
// <20><EFBFBD><E8B2BB><EFBFBD>ͺϲ<CDBA>
else if (idx > 0) {
mergeLeft(_node, idx); // <20><><EFBFBD><EFBFBD><EFBFBD>ֵܺϲ<DCBA>
}
else if (idx < _node->children.size() - 1) {
mergeRight(_node, idx); // <20><><EFBFBD><EFBFBD><EFBFBD>ֵܺϲ<DCBA>
}
}
}
}
/*
template<class T>
inline void BPlusTree<T>::fixUnderflow(Node<T>* _node)
{
//<2F><><EFBFBD><EFBFBD><EFBFBD>Ա߽<D4B1>
//<2F><EFBFBD><E8B2BB><EFBFBD>ͺϲ<CDBA>
}*/
template<class T>
inline T& BPlusTree<T>::getMin(Node<T>* _node)
{
if (!_node || _node->keys.empty()) {
throw std::runtime_error("Empty node has no minimum key");
}
Node<T>* cur = _node;
while (!cur->isLeaf) {
cur = cur->children[0]; // <20>ص<EFBFBD>:<3A><>С<EFBFBD>ģ<EFBFBD>һֱ<D2BB><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
return cur->keys[0]; // <20><><EFBFBD><EFBFBD>Ҷ<EFBFBD>ӵĵ<D3B5>һ<EFBFBD><D2BB> key
}
template<class T>
inline void BPlusTree<T>::borrowLeft(Node<T>* _node, int _i)
{
// Ҷ<>ӽڵ<D3BD>
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]; // <20><><EFBFBD>¸<EFBFBD><C2B8>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key
}
// <20>ڲ<EFBFBD><DAB2>ڵ<EFBFBD>
else {
Node<T>* left = _node->children[_i - 1];
Node<T>* cur = _node->children[_i];
// <20><><EFBFBD>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key <20>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>
cur->keys.insert(cur->keys.begin(), _node->keys[_i - 1]);
// <20><><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD> key <20>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>ڵ<EFBFBD>
_node->keys[_i - 1] = left->keys.back();
left->keys.pop_back();
// <20><><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӽڵ<D3BD><DAB5>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD><DAB5>ף<EFBFBD><D7A3><EFBFBD><EFBFBD>ź<EFBFBD><C5BA><EFBFBD>һ<EFBFBD>𶯣<EFBFBD>
Node<T>* c = left->children.back();
left->children.pop_back();
cur->children.insert(cur->children.begin(), c);
}
}
template<class T>
inline void BPlusTree<T>::borrowRight(Node<T>* _node, int _i)
{
// Ҷ<>ӽڵ<D3BD>
if (_node->isLeaf) {
Node<T>* cur = _node->children[_i];
Node<T>* right = _node->children[_i + 1];
// <20><><EFBFBD>ֵܵ<D6B5>һ<EFBFBD><D2BB> key <20>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD>ĩβ
T tmp = right->keys.front();
right->keys.erase(right->keys.begin());
cur->keys.push_back(tmp);
// <20><><EFBFBD>¸<EFBFBD><C2B8>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key
_node->keys[_i] = right->keys.front();
}
// <20>ڲ<EFBFBD><DAB2>ڵ<EFBFBD>
else {
Node<T>* cur = _node->children[_i];
Node<T>* right = _node->children[_i + 1];
// <20><><EFBFBD>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key <20>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD>ĩβ
cur->keys.push_back(_node->keys[_i]);
// <20><><EFBFBD>ֵܵ<D6B5>һ<EFBFBD><D2BB> key <20>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>ڵ<EFBFBD>
_node->keys[_i] = right->keys.front();
right->keys.erase(right->keys.begin());
// <20><><EFBFBD>ֵܵ<D6B5>һ<EFBFBD><D2BB><EFBFBD>ӽڵ<D3BD><DAB5>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD>ĩβ
Node<T>* c = right->children.front();
right->children.erase(right->children.begin());
cur->children.push_back(c);
}
}
/*
template<class T>
inline void BPlusTree<T>::mergeLeft(Node<T>* _node, int _i)
{
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD>
Node<T>* c = _node->children[_i];
_node->keys.erase(_node->keys.begin() + _i);
//<2F>ϲ<EFBFBD>
_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<class T>
inline void BPlusTree<T>::mergeLeft(Node<T>* _node, int _i)
{
Node<T>* left = _node->children[_i - 1];
Node<T>* cur = _node->children[_i];
// 1. <20><><EFBFBD>ڵ<EFBFBD> key <20>ƶ<EFBFBD> / ɾ<><C9BE>
if (!left->isLeaf) {
// <20>ڲ<EFBFBD><DAB2>ڵ㣺<DAB5><E3A3BA><EFBFBD>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key <20>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>ֵ<EFBFBD>ĩβ
left->keys.push_back(_node->keys[_i - 1]);
}
_node->keys.erase(_node->keys.begin() + (_i - 1));
// 2. <20>ϲ<EFBFBD> keys
left->keys.insert(left->keys.end(), cur->keys.begin(), cur->keys.end());
// 3. <20>ϲ<EFBFBD> children<65><6E><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2>ڵ㣩
if (!left->isLeaf) {
left->children.insert(left->children.end(), cur->children.begin(), cur->children.end());
}
// 4. Ҷ<>ӽڵ<D3BD><DAB5><EFBFBD><EFBFBD><EFBFBD> next ָ<><D6B8>
if (left->isLeaf) {
left->next = cur->next;
}
// 5. ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD> children <20>еĵ<D0B5>ǰ<EFBFBD>ڵ<EFBFBD>
_node->children.erase(_node->children.begin() + _i);
}
template<class T>
inline void BPlusTree<T>::mergeRight(Node<T>* _node, int _i)
{
Node<T>* cur = _node->children[_i];
Node<T>* right = _node->children[_i + 1];
// 1. <20><><EFBFBD>ڵ<EFBFBD> key
if (!cur->isLeaf) {
// <20>ڲ<EFBFBD><DAB2>ڵ㣺<DAB5><E3A3BA><EFBFBD>ڵ<EFBFBD><DAB5>ֽ<EFBFBD> key <20>Ƶ<EFBFBD><C6B5><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD>ĩβ
cur->keys.push_back(_node->keys[_i]);
}
// 2. <20>ϲ<EFBFBD> keys
cur->keys.insert(cur->keys.end(), right->keys.begin(), right->keys.end());
// 3. <20>ϲ<EFBFBD> children<65><6E><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2>ڵ㣩
if (!cur->isLeaf) {
cur->children.insert(cur->children.end(), right->children.begin(), right->children.end());
}
// 4. Ҷ<>ӽڵ<D3BD><DAB5><EFBFBD><EFBFBD><EFBFBD> next ָ<><D6B8>
if (cur->isLeaf) {
cur->next = right->next;
}
// 5. ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD> key
_node->keys.erase(_node->keys.begin() + _i);
// 6. ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD> children <20>е<EFBFBD><D0B5><EFBFBD><EFBFBD>ֵ<EFBFBD>
_node->children.erase(_node->children.begin() + _i + 1);
}
template<class T>
inline void BPlusTree<T>::insert(const T& _key)
{
//<2F><><EFBFBD>Ѹ<EFBFBD>
if (root->keys.size() == M - 1) {
Node<T>* newr = new Node<T>(false);
newr->children.push_back(root);
splitChild(newr, 0);
root = newr;
}
//<2F><><EFBFBD><EFBFBD>
insertNonFull(root, _key);
}
template<class T>
inline Node<T>* BPlusTree<T>::search(const T& _key)
{
Node<T>* 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) {
//<2F>ж<EFBFBD><D0B6>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>tmp<6D><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ٸ<EFBFBD><D9B8>ݷ<EFBFBD><DDB7>ص<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><E9BCB4>
return tmp;
}
else {
tmp = tmp->children[idx];
}
}
return nullptr;
}
template<class T>
inline void BPlusTree<T>::areaSearch(const T& _low, const T& _up)
{
//<2F><><EFBFBD>ò<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD>search<63><68><EFBFBD><EFBFBD><EFBFBD>صĶ<D8B5><C4B6><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
Node<T>* 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<class T>
inline void BPlusTree<T>::displayLeaf()
{
Node<T>* tmp = firstLeaf;
while (tmp) {
for (auto x : tmp->keys) std::cout << x << " ";
tmp = tmp->next;
std::cout << "C ";
}
std::cout << std::endl;
}
template<class T>
inline void BPlusTree<T>::erase(const T& _key)
{
if (!root) return;
//<2F>ݹ<EFBFBD>ɾ<EFBFBD><C9BE>
erase(root, _key);
if (root->isLeaf && root->keys.size() == 0) {
root = root->children[0];
}
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <vector>
template <class T>
class Node {
public:
//ʹ<>õ<EFBFBD>ʱ<EFBFBD><CAB1>T<EFBFBD><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>pair
std::vector<T> keys;
std::vector<Node<T>*> children;
bool isLeaf;
Node<T>* next;
Node() = delete;
Node(bool _isLeaf) : isLeaf(_isLeaf), next(nullptr) {}
Node(bool _isLeaf, Node<T>* _next) : isLeaf(_isLeaf), next(_next) {}
};

View File

@@ -0,0 +1,25 @@
#include "BPlusTree.h"
using namespace std;
int main() {
BPlusTree<int> 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
*/

View File

@@ -312,3 +312,4 @@
--- ---
要不要我帮你把“3 种情况 → 转化为 2 种简单情况”的流程画成一个 **决策图(删除流程图)**?这样会更直观。 要不要我帮你把“3 种情况 → 转化为 2 种简单情况”的流程画成一个 **决策图(删除流程图)**?这样会更直观。