Files
Data-Structure/BinaryTree/BalanceTree/BPlus-Tree/BPlusTree.h
2025-08-27 17:33:56 +08:00

379 lines
9.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include "Node.h"
#include <iostream>
#include <algorithm>
template <class T>
class BPlusTree {
private:
Node<T>* root;
int M;
Node<T>* firstLeaf;//做链表范围查找
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);
//中点这个就是阶数的计算方式了之前用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<class T>
inline void BPlusTree<T>::insertNonFull(Node<T>* _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<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;
//前一半和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<T>* 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<class T>
inline void BPlusTree<T>::fixUnderflow(Node<T>* _node)
{
//先找旁边借
//借不到就合并
}*/
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]; // 重点:最小的,一直往左子树走
}
return cur->keys[0]; // 最左叶子的第一个 key
}
template<class T>
inline void BPlusTree<T>::borrowLeft(Node<T>* _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<T>* left = _node->children[_i - 1];
Node<T>* 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<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)
{
// 叶子节点
if (_node->isLeaf) {
Node<T>* cur = _node->children[_i];
Node<T>* 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<T>* cur = _node->children[_i];
Node<T>* 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<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)
{
//处理父节点多出的东西
Node<T>* 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<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. 父节点 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<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. 父节点 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<class T>
inline void BPlusTree<T>::insert(const T& _key)
{
//分裂根
if (root->keys.size() == M - 1) {
Node<T>* newr = new Node<T>(false);
newr->children.push_back(root);
splitChild(newr, 0);
root = newr;
}
//插入
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) {
//判断是否溢出如果范围搜索需要用到那么均需要返回tmp单个索引的时候再根据返回的值搜索一遍即可
return tmp;
}
else {
tmp = tmp->children[idx];
}
}
return nullptr;
}
template<class T>
inline void BPlusTree<T>::areaSearch(const T& _low, const T& _up)
{
//最好不直接用search返回的东西不一样
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;
//递归删除
erase(root, _key);
if (root->isLeaf && root->keys.size() == 0) {
root = root->children[0];
}
}