标签:child arch efi 跳过 hot 有用 for highlight 情况
#ifndef BTree_hpp
#define BTree_hpp
#include "Vector.hpp"
#define BTNodePosi(T) BTNode<T>* //B-树节点位置
//B-树节点模版类
template <typename T> struct BTNode{
BTNodePosi(T) parent; //父节点
Vector<T> key; //关键码向量
Vector<BTNodePosi(T)> child; //孩子向量(其长度总比key多一)
BTNode() {
parent = NULL;
child.insert(0, NULL);
}
BTNode(T e,BTNodePosi(T) lc = NULL,BTNodePosi(T) rc = NULL) {
parent = NULL;
key.insert(0, e);
child.insert(0, lc);
child.insert(1, rc); //一个关键码,两个孩子
if (lc) {
lc->parent = this;
}
if (rc) {
rc -> parent = this;
}
}
};
//B-树模版类
template <typename T> class BTree{
protected:
int _size; //存放的关键码总数
int _order; //B-树的阶次,至少为3----创建时指定,一般不能修改
BTNodePosi(T) _root; //根节点
BTNodePosi(T) _hot; //BTree::search()最后访问的非空(除非树空)的节点位置
void solveOverflow(BTNodePosi(T)); //因插入而上溢之后的分裂处理
void solveUnderflow(BTNodePosi(T)); //因删除而下溢之后的合并处理
public:
BTree(int order = 3) : _order(order), _size(0) {
_root = new BTNode<T>();
}
~BTree() {
if (_root) {
delete _root;
}
}
int const order() {
return _order;
}
int const size() {
return _size;
}
BTNodePosi(T) & root() {
return _root;
}
bool empty() const {
return !_root;
}
BTNodePosi(T) search(const T& e);
bool insert(const T& e);
bool remove(const T& e);
};
//在B-树中查找关键码e
template <typename T> BTNodePosi(T) BTree<T>::search(const T &e) {
BTNodePosi(T) v = _root;
_hot = NULL;
while (v) {
Rank r = v->key.search(e);//在当前节点中,找到不大于e的最大关键码
if ( (0 <= r) && (e == v->key[r]) ) {
return v; //成功:在当前节点中命中目标关键码
}
_hot = v;
v = v->child[r+1]; //否则,转入对应子树(_hot指向其父)---需做I/O,最费时间
}//这里在向量内是二分查找,但对通常的_order可直接顺序查找
return NULL;//失败:最终抵达外部节点
}
//将关键码e插入B树中
template <typename T> bool BTree<T>::insert(const T &e) {
BTNodePosi(T) v = search(e);
if (v) {
return false;
}
Rank r = _hot->key.search(e);
_hot->key.insert(r+1, e); //将关键码插至对应的位置
_hot->child.insert(r+2, NULL); //创建一个空子树指针
_size++; //更新全树规模
solveOverflow(_hot); //如有必要,需做分裂
return true; //插入成功
}
//关键码插入后若节点上溢,则做节点分裂处理
template <typename T>
void BTree<T>::solveOverflow(BTNodePosi(T) v) {
if (_order >= v->child.size()) {
return; //递归基:当前节点并为上溢
}
Rank s = _order / 2; //轴点(此时应有_order=key.size()=child.size()-1)
BTNodePosi(T) u = new BTNode<T>(); //注意:新节点已有一个空孩子
for (Rank j = 0; j < _order-s-1; j++) {
//v右侧_order-s-1个孩子及关键码分裂为右侧节点
u -> child.insert(j, v->child.remove(s+1)); //逐个移动效率低
u -> key.insert(j, v->key.remove(s+1) ); //此策略可改进
}
u -> child[_order-s-1] = v->child.remove(s+1); //移动v最靠右的孩子
if (u -> child[0]) {
//若u的孩子们非空,则令他们的父节点统一
for (Rank j = 0; j < _order-s; j++) {
u -> child[j]->parent = u; //指向u
}
}
BTNodePosi(T) p = v -> parent; //v当前的父节点p
if (!p) {
_root = p = new BTNode<T>();
p -> child[0] = v;
v -> parent = p;
}
Rank r = 1 + p -> key.search(v -> key[0]); //p中指向u的指针的秩
p -> key.insert(r, v -> key.remove(s)); //轴点关键码上升
p -> child.insert(r + 1, u);
u -> parent = p; //新节点u与父节点p互联
solveOverflow(p); //上升一层,如有必要则继续分裂-----至多递归O(logn)层
}
//从BTree树中删除关键码e
template <typename T> bool BTree<T>::remove(const T &e) {
BTNodePosi(T) v = search(e);
if (!v) {
return false;
}
Rank r = v -> key.search(e); //确定目标关键码在节点v中的秩
if (v -> child[0]) {
//若v非叶子,则e的后继必属于某叶节点
BTNodePosi(T) u = v->child[r+1]; //在右子树中一直向左,即可找出e的后继,并与之交换位置
while ( u->child[0] ) {
u = u -> child[0];
}
v -> key[r] = u -> key[0];
v = u;
r = 0;
}//至此,v必然位于最底层,且其中第r个关键码就是待删除者
//删除额,以及其下两个外部节点之一
v -> key.remove(r);
v -> child.remove(r+1);
_size--;
solveUnderflow(v); //如有必要,需做旋转或合并
return true;
}
//关键码删除后若节点下溢,则做节点旋转或合并处理
template <typename T>
void BTree<T>::solveUnderflow(BTNodePosi(T) v){
if ( (_order + 1 ) / 2 <= v->child.size() ) {
return;
}
BTNodePosi(T) p = v -> parent;
if (!p) { //递归基:已到根节点,没有孩子的下限
if (!v->key.size() && v->child[0]) {
//但倘若作为树根的v已不包含关键码,却有(唯一的)非空孩子,则这个节点可被跳过,并因不再有用而销毁
_root = v -> child[0];
_root -> parent = NULL;
v -> child[0] = NULL;
delete v;
}
return;
}
Rank r = 0;
while (p->child[r] != v) {
r++;
}
//情况1:向左兄弟借关键码
if (0 < r) {
BTNodePosi(T) ls = p -> child[r-1]; //左兄弟必存在
if ( (_order + 1) /2 < ls->child.size()) {
//若该兄弟足够胖,则p借出一个关键码给v(作为最小关键码)
v -> key.insert(0, p->key[r-1]);
p -> key[r-1] = ls -> key.remove(ls->key.size()-1);
v -> child.insert(0, ls->child.remove(ls->child.size() - 1));
//同时ls的最右侧孩子过继给v
if (v->child[0]) {
v->child[0]->parent = v; //作为v的最左侧孩子
}
return; //至此,通过右旋已完成当前层(以及所有层)的下溢处理
}
}
//情况2:向右兄弟借关键码
if (p -> child.size() - 1 > r) {
//若v不是p的最后一个孩子,则右兄弟必存在,若该兄弟足够胖
//则p借出一个关键码给v
BTNodePosi(T) rs = p -> child[r+1];
if ( (_order+1)/2 < rs->child.size()) {
v -> key.insert(v->key.size(), p->key[r]);
p -> key[r] = rs -> key.remove(0); //ls的最小关键码转入p
v -> child.insert(v->child.size(), rs->child.remove(0));
//同时rs的最左侧孩子过继给v
if (v->child[v->child.size()-1]) {
v->child[v->child.size()-1] -> parent = v;
}
return;//至此,通过左旋已完成当前层(以及所有层)的下溢处理
}
}
//情况3:左右兄弟要么为空(但不可能同时),要么都太"瘦" ----- 合并
if (0 < r) { //与左兄弟合并
BTNodePosi(T) ls = p->child[r-1]; //左兄弟必存在
ls->key.insert(ls->key.size(), p->key.remove(r-1));
p->child.remove(r);
//p的第r-1个关键码转入ls,v不再是p的第r个孩子
ls -> child.insert(ls->child.size(), v->child.remove(0));
//v的最左侧孩子过继给ls做最右侧孩子
if (ls->child[ls->child.size()-1]) {
ls->child[ls->child.size()-1] -> parent = ls;
}
//v剩余的关键码和孩子,一次转入ls
while (!v->key.empty()) {
ls->key.insert(ls->key.size(), v->key.remove(0));
ls->child.insert(ls->child.size(), v->child.remove(0));
if (ls->child[ls->child.size() - 1]) {
ls->child[ls->child.size() - 1] -> parent = ls;
}
}
delete v;
}else{ //与右兄弟合并
BTNodePosi(T) rs = p -> child[r+1]; //右兄弟必存在
rs->key.insert(0, p->key.remove(r));
p->child.remove(r);
//p的第r个关键码转入rs,v不再是p的第r个孩子
rs->child.insert(0, v->child.remove(v->child.size() - 1));
if (rs->child[0]) {
rs->child[0] -> parent = rs;
}
while (!v->key.empty()) {
//v剩余的关键码和孩子,一次转入rs
rs->key.insert(0, v->key.remove(v->key.size()-1 ));
rs->child.insert(0, v->child.remove(v->child.size()-1));
if (rs->child[0]) {
rs->child[0] -> parent = rs;
}
}
delete v;
}
solveUnderflow(p); // 上升一层,如有必要则继续分裂---至多递归O(logn)层
return;
}
#endif /* BTree_hpp */
标签:child arch efi 跳过 hot 有用 for highlight 情况
原文地址:https://www.cnblogs.com/gkp307/p/9621098.html