C++实现B-Tree(B-树)

本文介绍了B-树的基本概念,展示了如何使用C++模板类实现B-树,包括节点结构、关键码处理、插入和删除操作,以及解决插入和删除操作导致的节点大小溢出问题。

参考:邓俊辉老师《数据结构C++语言实现》

B-树节点由多个关键码组成,在数据结构中用向量表示,同理,关键码的孩子也存在向量中,结构如下:

key:                             key0     key1     key2     key3     key4                                                (存数值)

child:                   child0     child1    child2   child3    child4  child5                                        (存指针)

BNode以及BTree定义:

//
// Created by Jayson on 2023/8/5.
//
#include <iostream>
#include "vector"
using namespace std;

template<typename T>
class BTNode{
public:
    BTNode<T>* parent;
    vector<T> key;
    vector<BTNode<T>*> child;

    BTNode(){//构造含有0个关键码的节点
        parent = NULL;
        child.push_back(NULL);
    }
    BTNode(T e,BTNode<T>* lc = NULL, BTNode<T>*rc = NULL){//构造含有一个关键码的节点
        parent = NULL;
        key.push_back(e);
        child.push_back(lc);
        child.push_back(rc);
        if(lc) lc->parent = this;
        if(rc) rc->parent = this;
    }
};

template<typename T>
class BTree{
public:
    BTNode<T>* _root;
    BTNode<T>* _hot;//搜索到节点的父亲,若搜索失败,则为"空节点"的父亲
    int _order;//B-树的阶,也就是child向量能包含元素的最大个数
    int _size;//关键码总数
    void solveOverFlow(BTNode<T>* v);//解决因为插入操作而产生的上溢
    void solveUnderFlow(BTNode<T>* v);//解决因为删除操作而产生的下溢

    BTree(int ord){
        _order = ord;
        _size = 0;
        _root = new BTNode<T>();
    }
    bool empty(){return !_root;}

    //查、插、删
    BTNode<T>* search(T e);
    bool insert(T e);
    bool remove(T e);
};

实现:

//辅助函数,在向量中查找,返回不大于该元素最大的秩,使用二分查找
template<typename T>
int binSearchInBTNode(vector<T> A,T e){
    if(A.size() == 0){
        return 0;
    }

    int lo = 0;
    int hi = A.size();
    while(lo<hi){
        int mid = (lo + hi) / 2;
        if(e < A[mid]){
            hi = mid;
        }else{
            lo = mid + 1;
        }
    }
    lo = lo - 1;
    return lo;
}

template<typename T>
BTNode<T>* BTree<T>::search(T e) {
    BTNode<T>* v = _root;
    _hot = NULL;
    while(v){
        int r = binSearchInBTNode(v->key,e);
        if( (r >= 0) && v->key[r] == e ) return v;
        _hot = v;
        v = v->child[r+1];
    }
    return NULL;
}

template<typename T>
bool BTree<T>::insert(T e) {
    BTNode<T>* v = search(e);
    if(v) return false;

    //查找失败,必失败于外部节点,_hot此时指向叶节点
    int r = binSearchInBTNode(_hot->key,e);
    _hot->key.insert(_hot->key.begin()+r+1,e);
    _hot->child.insert(_hot->child.begin()+r+2,NULL);
    _size++;
    solveOverFlow(_hot);
    return true;
}
template<typename T>
void BTree<T>::solveOverFlow(BTNode<T> *v) {
    if(v->child.size() <= _order) return;

    int rank = v->key.size() / 2;
    BTNode<T>* newNode = new BTNode<T>();
    for(int i = rank+1; i < v->key.size(); i++){
        newNode->key.push_back(v->key[i]);
    }
    newNode->child.clear();
    for(int i =rank+1; i < v->child.size(); i++){
        newNode->child.push_back(v->child[i]);
    }

    for(int i = 0; i < newNode->child.size(); i++){
        if(newNode->child[i])
            newNode->child[i]->parent = newNode;
    }

    T value = v->key[rank];//保存上溢节点值
    v->key.resize(rank);

    BTNode<T>* p = v->parent;
    if(!p){//当前节点已经是根,溢出称为新根
        _root = new BTNode<T>();
        p = _root;
        p->child[0] = v;
        p->child[1] = newNode;
        v->parent = p;
        newNode->parent = p;
        p->key.push_back(value);
    }else{
        int r = binSearchInBTNode(p->key,v->key[0]);//注意这里search的元素是key[0]
        p->key.insert(p->key.begin()+r+1,value);
        p->child.insert(p->child.begin()+r+2,newNode);
        newNode->parent = p;
    }
    solveOverFlow(p);
}

template<typename T>
bool BTree<T>::remove(T e) {
    BTNode<T>* v = search(e);
    if(!v) return false;

    int rank = binSearchInBTNode(v->key,e);
    if(v->child[0]){
        //v不是叶子节点
        BTNode<T>* u = v->child[rank+1];
        while(u->child[0]){
            u = u->child[0];
        }
        v->key[rank] = u->key[0];
        v = u;
        rank = 0;
    }
    v->key.erase(v->key.begin()+rank);
    v->child.erase(v->key.begin()+rank+1);
    _size--;
    solveUnderFlow(v);
}

template<typename T>
void BTree<T>::solveUnderFlow(BTNode<T> *v) {
    if( v->child.size() >= ((_order+1)/2) )return;//递归基:阶数满足条件

    BTNode<T>* p = v->parent;
    if(!p){//递归基:根节点size为0
        if(v->key.size()==0 && v->child[0]){
            _root = v->child[0];
            v->child[0]->parent = NULL;
            v->child[0] = NULL;
        }
        return;
    }

    int r = 0;
    while(p->child[r] != v){
        r++;
    }//确定v是r的第几个孩子

    //case1
    if(r>0){//左兄弟必然存在   此时p->child[r] == v;p->child[r-1] == 左兄弟
        BTNode<T>* ls = p->child[r-1];
        if(ls->child.size() >= ((_order+1)/2)+1){//左兄弟能借
            v->key.insert(v->key.begin(),p->key[r-1]);
            T value = ls->key[ls->key.size()-1];
            p->key[r-1] = value;
            v->child.insert(v->child.begin(),ls->child[ls->child.size()-1]);
            if(ls->child[ls->child.size()-1]) v->child[0]->parent = v;
            ls->key.resize(ls->key.size()-1);
            ls->child.resize(ls->child.size()-1);
            return;//修复完成
        }
    }
    //case2
    if(r<p->child.size()-1){//右兄弟必然存在
        BTNode<T>* rs = p->child[r+1];
        if(rs->child.size() >= ((_order+1)/2)+1)){//右兄弟能借
            v->key.push_back(p->key[r-1]);
            T value = rs->key[0];
            p->key[r-1] = value;
            v->child.push_back(rs->child[0]);
            if(rs->child[0]) rs->child[0]->parent = v;
            rs->key.erase(rs->key.begin());
            rs->child.erase(rs->child.begin());
            return;//修复完成
        }
    }

    //case3左右兄弟都无法借关键码,因此需要合并
    if(r>0){//与左兄弟合并
        BTNode<T>* ls = p->child[r-1];
        ls->key.push_back(p->key[r-1]);
        p->key.erase(p->key.begin()+r-1);
        p->child.erase(p->child.begin()+r);
        for(int i = 0; i<v->key.size(); i++){
            ls->key.push_back(v->key[i]);
        }
        for(int i = 0; i<v->child.size(); i++){
            ls->child.push_back(v->child[i]);
            if(v->child[i]) v->child[i]->parent = ls;
        }
        delete v;
    }else{//与右兄弟合并
        BTNode<T>* rs = p->child[r+1];
        rs->key.insert(rs->key.begin(),p->key[r]);
        p->child.erase(p->child.begin()+r);
        p->key.erase(p->key.begin()+r);
        for(int i = v->key.size()-1;i>=0;i--){
            rs->key.insert(rs->key.begin(),v->key[i]);
        }
        for(int i = v->child.size()-1; i>=0;i--){
            rs->child.insert(rs->child.begin(),v->child[i]);
            if(v->child[i]) v->child[i]->parent = rs;
        }
        delete v;
    }

    solveUnderFlow(p);
    return;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值