Files
Data-Structure/BinaryTree/BalanceTree/B-Tree/BTree.h
2025-08-26 19:13:51 +08:00

136 lines
3.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 <iostream>
#include "Node.h"
#include <algorithm>
template <class T>
class BTree {
private:
Node<T>* root;
int t; //*B-树的阶数(节点最大元素数的一半)
//这里的t最后体现在每个节点上都是t - 1 到 2t - 1
void splitChild(Node<T>* _node, int _n);
void insertNonFull(Node<T>* _node, const T& _key);
void inorder(Node<T>* _n) {
if (!_n) return;
int i = 0;
//关注中序的时候inorder(children[0]) -> inorder(key[0]) -> inorder(children[1])... 这样保证升序
for (i = 0; i < _n->keys.size(); i++) {
if (i < _n->children.size()) inorder(_n->children[i]);
std::cout << _n->keys[i] << " ";
}
//已经i++
if (i < _n->children.size()) inorder(_n->children[i]);
std::cout << std::endl;
}
public:
BTree() = delete;
BTree(int _t) : t(_t), root(nullptr) {}
void display() { inorder(root); }
void insert(const T& _key);
bool search(Node<T>* _node, const T& _key);
void erase(const T& _key);
};
template<class T>
inline void BTree<T>::splitChild(Node<T>* _pt, int _i)
{
//_pt-父节点//_i-第几个子节点//t-中间元素
Node<T>* p = _pt->children[_i];
Node<T>* tmp = new Node<T>(p->isLeaf);
int mid = t - 1;
//复制mid右侧
for (int i = 0; i < mid; i++) {
tmp->keys.push_back(p->keys[t + i]);
}
//不是叶子节点-复制孩子
if (!p->isLeaf) {
for (int i = 0; i < t; i++) {
tmp->children.push_back(p->children[i + t]);
}
}
T middlekey = p->keys[mid];
//保留左侧
p->keys.resize(mid);
if (!p->isLeaf) p->children.resize(t);//t = mid + 1
//增加孩子
_pt->children.insert(_pt->children.begin() + _i + 1, tmp);
//提取中间元素插入上面
_pt->keys.insert(_pt->keys.begin() + _i, middlekey);
}
template<class T>
inline void BTree<T>::insertNonFull(Node<T>* _node, const T& _key)
{
int i = _node->keys.size() - 1;
//是叶子节点-先插入后排序O(n)
if (_node->isLeaf) {
_node->keys.push_back(_key);
//向后移位
while (i >= 0 && _node->keys[i] > _key) {
_node->keys[i + 1] = _node->keys[i];
i--;
}
_node->keys[i + 1] = _key;
}
//不是叶子节点,递归向下寻找叶子节点
else {
while (i >= 0 && _node->keys[i] > _key) {
i--;
}
i++;//找到children位置
//节点满了先分裂
if (_node->children[i]->keys.size() == 2 * t - 1) {
splitChild(_node, i);
//分裂提升后可能改变关键字位置
if (_key > _node->keys[i]) i++;
}
insertNonFull(_node->children[i], _key);
}
}
template<class T>
inline void BTree<T>::insert(const T& _key)
{
//1-树空无root
if (!root) {
root = new Node<T>(true);
root->keys.push_back(_key);
}
//2-有root正常插入
else {
//root满分裂根节点
//重点关注:插入的时候,不管关键字是否上升到根节点,如果根节点满了,都要分裂以防万一
if (root->keys.size() == 2*t - 1) {
Node<T>* _root = new Node<T>(false);
_root->children.push_back(root);
splitChild(_root, 0);
root = _root;
}
//继续执行
insertNonFull(root, _key);
}
//当 t = 2root 目前有 2 个元素插入一个新元素后root 会变成 3 个元素(满节点)。此时还不会分裂,分裂逻辑只在下一次插入超过 3 个元素时触发。
}
template<class T>
inline bool BTree<T>::search(Node<T>* _node, const T& _key)
{
//可以递归做
Node<T>* tmp = _node;
int i = 0;
while (tmp->keys[i] < _key && i < tmp->keys.size()) i++;
if (tmp->keys[i] == _key) return true;
if(tmp->isLeaf) return false;
return search(_node->children[i], _key);
}
template<class T>
inline void BTree<T>::erase(const T& _key)
{
//1-删除叶子
}