B树的创建

来源:互联网 发布:霍元甲 歌词 知乎 编辑:程序博客网 时间:2024/06/06 01:31

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;}
原创粉丝点击