This commit is contained in:
e2hang
2025-08-26 19:21:23 +08:00
parent fe9d51456b
commit 3eb93c256c
3 changed files with 434 additions and 1 deletions

View File

@@ -0,0 +1,241 @@
#include <iostream>
#include <vector>
using namespace std;
template <class T>
struct Node {
bool leaf; // 是否为叶子节点
vector<T> keys; // 存储关键字
vector<Node*> children; // 孩子节点指针
Node(bool _leaf) : leaf(_leaf) {}
};
template <class T>
class BTree {
public:
BTree(int _t) : t(_t), root(nullptr) {}
void insert(const T& key); // 插入关键字
void remove(const T& key); // 删除关键字
void traverse() { traverse(root); cout << endl; } // 中序遍历
private:
Node<T>* root;
int t; // 最小度数
// ----------- 插入相关辅助函数 -----------
void insertNonFull(Node<T>* node, const T& key); // 在非满节点插入
void splitChild(Node<T>* parent, int idx); // 分裂子节点
// ----------- 删除相关辅助函数 -----------
void remove(Node<T>* node, const T& key); // 递归删除
void removeFromLeaf(Node<T>* node, int idx); // 从叶子节点删除
void removeFromNonLeaf(Node<T>* node, int idx); // 从非叶子节点删除
T getPredecessor(Node<T>* node, int idx); // 找前驱
T getSuccessor(Node<T>* node, int idx); // 找后继
void fill(Node<T>* node, int idx); // 保证孩子节点至少 t-1 个关键字
void borrowFromPrev(Node<T>* node, int idx); // 从左兄弟借一个关键字
void borrowFromNext(Node<T>* node, int idx); // 从右兄弟借一个关键字
void merge(Node<T>* node, int idx); // 与右兄弟合并
// ----------- 遍历辅助函数 -----------
void traverse(Node<T>* node);
};
// ---------------------- 插入相关 ----------------------
template<class T>
void BTree<T>::insert(const T& key) {
if (!root) { // 树空
root = new Node<T>(true);
root->keys.push_back(key);
} else {
// 根节点满,先分裂根节点
if (root->keys.size() == 2*t - 1) {
Node<T>* s = new Node<T>(false);
s->children.push_back(root);
splitChild(s, 0);
root = s;
}
insertNonFull(root, key); // 插入非满节点
}
}
template<class T>
void BTree<T>::insertNonFull(Node<T>* node, const T& key) {
int i = node->keys.size() - 1;
if (node->leaf) { // 叶子节点直接插入
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++;
if (node->children[i]->keys.size() == 2*t-1) {
splitChild(node, i); // 分裂满子节点
if (node->keys[i] < key) i++;
}
insertNonFull(node->children[i], key);
}
}
template<class T>
void BTree<T>::splitChild(Node<T>* parent, int idx) {
Node<T>* y = parent->children[idx];
Node<T>* z = new Node<T>(y->leaf);
// 把 y 的后 t-1 个关键字移动到 z
for (int j = 0; j < t-1; j++) z->keys.push_back(y->keys[j+t]);
if (!y->leaf) {
for (int j = 0; j < t; j++) z->children.push_back(y->children[j+t]);
y->children.resize(t);
}
y->keys.resize(t-1); // 保留前 t-1 个关键字
parent->children.insert(parent->children.begin()+idx+1, z);
parent->keys.insert(parent->keys.begin()+idx, y->keys[t-1]); // 中间关键字上移
}
// ---------------------- 删除相关 ----------------------
template<class T>
void BTree<T>::remove(const T& key) {
if (!root) return;
remove(root, key);
// 如果根节点被删除后没有关键字,调整 root
if (root->keys.empty()) {
Node<T>* oldRoot = root;
if (root->leaf) root = nullptr;
else root = root->children[0];
delete oldRoot;
}
}
template<class T>
void BTree<T>::remove(Node<T>* node, const T& key) {
int idx = 0;
while (idx < node->keys.size() && node->keys[idx] < key) idx++;
if (idx < node->keys.size() && node->keys[idx] == key) {
if (node->leaf) removeFromLeaf(node, idx); // 情况1: 叶子节点直接删除
else removeFromNonLeaf(node, idx); // 情况2: 内部节点
} else {
if (node->leaf) return; // key不存在
bool flag = (idx == node->keys.size());
// 如果孩子节点关键字不足 t 个,需要调整
if (node->children[idx]->keys.size() < t) fill(node, idx);
if (flag && idx > node->keys.size()) remove(node->children[idx-1], key);
else remove(node->children[idx], key);
}
}
template<class T>
void BTree<T>::removeFromLeaf(Node<T>* node, int idx) {
// 叶子节点直接删除关键字
node->keys.erase(node->keys.begin() + idx);
}
template<class T>
void BTree<T>::removeFromNonLeaf(Node<T>* node, int idx) {
T k = node->keys[idx];
// 如果左孩子关键字 >= t用前驱替换
if (node->children[idx]->keys.size() >= t) {
T pred = getPredecessor(node, idx);
node->keys[idx] = pred;
remove(node->children[idx], pred);
}
// 如果右孩子关键字 >= t用后继替换
else if (node->children[idx+1]->keys.size() >= t) {
T succ = getSuccessor(node, idx);
node->keys[idx] = succ;
remove(node->children[idx+1], succ);
}
// 左右孩子都不足 t则合并孩子
else {
merge(node, idx);
remove(node->children[idx], k);
}
}
template<class T>
T BTree<T>::getPredecessor(Node<T>* node, int idx) {
Node<T>* cur = node->children[idx];
while (!cur->leaf) cur = cur->children.back();
return cur->keys.back();
}
template<class T>
T BTree<T>::getSuccessor(Node<T>* node, int idx) {
Node<T>* cur = node->children[idx+1];
while (!cur->leaf) cur = cur->children[0];
return cur->keys[0];
}
template<class T>
void BTree<T>::fill(Node<T>* node, int idx) {
// 尝试从兄弟借关键字,如果不够则合并
if (idx != 0 && node->children[idx-1]->keys.size() >= t)
borrowFromPrev(node, idx);
else if (idx != node->keys.size() && node->children[idx+1]->keys.size() >= t)
borrowFromNext(node, idx);
else {
if (idx != node->keys.size()) merge(node, idx);
else merge(node, idx-1);
}
}
template<class T>
void BTree<T>::borrowFromPrev(Node<T>* node, int idx) {
Node<T>* child = node->children[idx];
Node<T>* sibling = node->children[idx-1];
// 将父节点关键字下移到 child 前面
child->keys.insert(child->keys.begin(), node->keys[idx-1]);
if (!child->leaf) child->children.insert(child->children.begin(), sibling->children.back());
node->keys[idx-1] = sibling->keys.back();
sibling->keys.pop_back();
if (!sibling->leaf) sibling->children.pop_back();
}
template<class T>
void BTree<T>::borrowFromNext(Node<T>* node, int idx) {
Node<T>* child = node->children[idx];
Node<T>* sibling = node->children[idx+1];
// 将父节点关键字下移到 child 后面
child->keys.push_back(node->keys[idx]);
if (!child->leaf) child->children.push_back(sibling->children[0]);
node->keys[idx] = sibling->keys[0];
sibling->keys.erase(sibling->keys.begin());
if (!sibling->leaf) sibling->children.erase(sibling->children.begin());
}
template<class T>
void BTree<T>::merge(Node<T>* node, int idx) {
Node<T>* child = node->children[idx];
Node<T>* sibling = node->children[idx+1];
// 将父节点关键字和 sibling 的关键字都移入 child
child->keys.push_back(node->keys[idx]);
child->keys.insert(child->keys.end(), sibling->keys.begin(), sibling->keys.end());
if (!child->leaf) child->children.insert(child->children.end(), sibling->children.begin(), sibling->children.end());
// 删除父节点中的关键字和 sibling 指针
node->keys.erase(node->keys.begin() + idx);
node->children.erase(node->children.begin() + idx + 1);
delete sibling;
}
// ---------------------- 遍历 ----------------------
template<class T>
void BTree<T>::traverse(Node<T>* node) {
if (!node) return;
int i;
for (i = 0; i < node->keys.size(); i++) {
if (!node->leaf) traverse(node->children[i]);
cout << node->keys[i] << " ";
}
if (!node->leaf) traverse(node->children[i]);
}