B树的创建

1.B树的概念

一棵M阶的(M>2) 的平衡二叉树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:

  • 根节点至少有两个孩子;
    原因:因为根节点至少有一个关键字,有两个指针域;

  • 每个非根节点至少有M/2-1(上取整)个关键字,至多有M-1个关键字,并且以升序排列;

  • 每个非根节点至少有M/2(上取整)个孩子,至多有M个孩子;
  • key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
  • 所有的叶子节点都在一层(由节点分裂可推导出);

2.为什么我们要引入B树
数据一般保存在磁盘上,若数据量过大则不能全部加载到内存,为了访问所有的数据,我们可以采用二叉搜索树的索引来保存数据,树的节点保存权值和磁盘的地址,这样查找时可以节约时间;
但是这并没有改善上述的问题,当数据量过大,树的高度则会增高,时间复杂度O(logN)还是太大,为了降低树的高度,减少时间复杂度,我们采用多叉搜索树;

3.B树的构建
首先我们应该清楚B树节点中包含了什么内容,如下所示
这里写图片描述

节点的分裂原则,如下例所示
这里写图片描述

再插入节点38和35
这里写图片描述

4.代码实现

#include<stdio.h>
#include<utility>
#include<iostream>
using namespace std;

template<class k,size_t M>
struct BTreeNode
{

    BTreeNode()
        :_size(0)
        ,_pParent(NULL)
    {
        for(size_t idx=0; idx<M+1; ++idx)
            _pSub[idx] = NULL;
    }

    k _keys[M];  //存储键值的数组
    BTreeNode* _pSub[M+1];  //存储孩子指针域的指针
    BTreeNode* _pParent;
    size_t _size;  //有效键值的个数
};


template<class k,size_t M>
class BTree
{
    typedef BTreeNode<k,M> Node;
public:
    BTree()
        :_pRoot(NULL)
    {}



    bool Insert(const k& key)
    {
        if(_pRoot == NULL)
        {
            _pRoot = new Node;
            _pRoot->_keys[0] = key;
            _pRoot->_size = 1;
            return true;
        }

        //查找插入节点的位置
        pair<Node*,int> ret = Find(key);
        if(ret.second > -1)
            return false;
        Node* pNode = ret.first;
        Node* pSub = NULL;
        k valuek = key;

        //将key值插入我们已经找到的节点
        while(true)
        {
            _Insert(pNode,valuek,pSub);

            if(pNode->_size < M)
                return true;
            //需要对节点进行分裂
            Node* pNewNode = new Node;
            size_t mid = M/2;
            size_t index = 0;
            size_t idx = 0;

            //搬移元素和孩子指针到pNewNode
            for(idx=mid+1; idx<pNode->_size; ++idx)
            {
                pNewNode->_keys[index] = pNode->_keys[idx];
                pNewNode->_pSub[index] = pNode->_pSub[idx];
                if(pNode->_pSub[idx])
                {
                    pNode->_pSub[idx]->_pParent = pNewNode->_pSub[index];
                    pNode->_pSub[idx] = NULL;
                }
                pNewNode->_size++;
                pNode->_size--;
                index++;
            }

            pNewNode->_pSub[index] = pNode->_pSub[idx];
            if(pNode->_pSub[idx])
            {
                pNode->_pSub[idx]->_pParent = pNewNode->_pSub[index];
                pNode->_pSub[idx] = NULL;
            }
            pNode->_size = pNode->_size - pNewNode->_size;

            //判断该节点是否为根节点
            if(pNode->_pParent == NULL)
            {
                _pRoot = new Node;
                _pRoot->_keys[0] = pNode->_keys[mid];

                _pRoot->_pSub[0] = pNode;
                pNode->_pParent = _pRoot;
                _pRoot->_pSub[1] = pNewNode;
                pNewNode->_pParent = _pRoot;
                _pRoot->_size++;
                return true;
            }
            else
            {
                valuek = pNode->_keys[mid];
                pNode = pNode->_pParent;
                pSub = pNewNode;
            }
        }
    }

    pair<Node*,int> Find(const k& key)
    {
        Node* pCur = _pRoot;
        Node* pParent = NULL;
        while(pCur)
        {
            int index = 0;
            while(index < pCur->_size)
            {
                if(pCur->_keys[index] > key)
                {
                    //pCur = pCur->_pSub[index];
                    break;
                }
                else if(pCur->_keys[index] < key)
                    index++;
                else
                    return pair<Node*,int>(pCur,index);
            }

            //if(key > pCur->_keys[index-1])
            pParent = pCur;
            pCur = pCur->_pSub[index];//当key比数组最后一个key值还大时
        }
        return pair<Node*,int>(pParent,-1);
    }
private:
    void _Insert(Node*& pNode,const k& key,Node* pSub)
    {
        int end = pNode->_size-1;
        while(end > -1)
        {
            if(pNode->_keys[end] > key)
            {
                pNode->_keys[end+1] = pNode->_keys[end];
                pNode->_pSub[end+2] = pNode->_pSub[end+1];
            }
            else
                break;
            end--;
        }
        pNode->_keys[end+1] = key;
        pNode->_pSub[end+2] = pSub;
        if(pSub)
            pSub->_pParent = pNode;
        pNode->_size++;
    }

private:
    Node* _pRoot;
};


测试代码:

#include"BTree.cpp"

void funtest()
{
    BTree<int,3> b;
    b.Insert(10);
    b.Insert(30);
    b.Insert(20);
    b.Insert(40);
    b.Insert(50);
    b.Insert(38);
    b.Insert(35);

}

int main()
{
    funtest();
    getchar();
    return 0;
}
  • 10
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值