⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmxbtree.cpp

📁 CMXBTree 的主要作用是在内存中建立一棵B+树
💻 CPP
📖 第 1 页 / 共 4 页
字号:
#ifndef _CMXBTREE_CPP_20010925
#define _CMXBTREE_CPP_20010925

//以下内容是 CMXBTree 的实现
//所有代码由 邬稳 编写于 2001.9
//版权所有:深圳科迈通讯技术有限公司 2001.9


#include "cmxbtree.h"

//排序
//参数 A 已经是排好序的队列
//Key 指向要插入的元素
//0     1      2      3      4
//|-----|--30--|--75--|--85--|
//   ^  nLo                 nHi
//   |
// 可用空间
//假设 Key == 15
template <class RECTYPE>
void CMXBTree<RECTYPE>::QuickSortData(DATA_CONTAINER **A, int nLo, int nHi, DATA_CONTAINER *Key)
{
    int i;
    int iHi = nHi;
    int iLo = nLo;
    bool bLoop = true;

    if( iHi == 0) //如果队列 A 中一个元素都没有
    {
        A[0] = Key;
        return;
    }

    if( iHi - iLo == 1) //如果队列 A 中只有一个元素
    {
        bLoop = false; //不用进入下面的 while 循环
        if( *(Key->pData) < *(A[iLo]->pData) )
            i = iLo;
        else i = iHi;
    }

    while( bLoop ) //队列 A 有两个或以上的元素时、才能进入 while 循环
    {
        //以下用二分法寻找可以插入的位置
        //这个位置就放在 i 中

        i = (iLo+iHi)/2;
        if( (i == iLo) && ( i== iHi ) )  break;
        if( *(Key->pData) < *(A[i-1]->pData)   )
        {
            iHi = i - 1;
            continue;
        }
        else
        if( *(Key->pData) < *(A[i]->pData)  )
        {
            break;
        }
        else iLo = i + 1;
    }
    
    int l;
    
    if( i == nLo && i > 0) //在最左边插入,而且左边有空
    {
        A[i-1] = Key;
        return ;
    }

    if( i == nHi && i < BTREE_DEGREE ) //在最右边插入,而且右边有空
    {
        A[i] = Key;
        return;
    }

    //需要在中间的某个地方插入
    if( nLo > 0 ) //左边有空,往左边推
    {
        for( l = 0; l < i-1 ; l ++)
            A[l] = A[l+1];
        A[i-1] = Key;
    }
    else //右边有空,往左边推
    {
        for( l = nHi-1; l >=i ; l --)
            A[l+1] = A[l];
        A[i] = Key;
    }
}

//申请一个新的索引叶
//如果不够内存,返回 NULL 
template <class RECTYPE>
CMXBTree<RECTYPE>::BTREE_INDEX_LEAF *CMXBTree<RECTYPE>::NewIndexLeaf( void )
{
    BTREE_INDEX_LEAF *pTmp = new BTREE_INDEX_LEAF;
    if ( !pTmp ) return NULL;
    
    m_nNewIndexLeaf ++;

    memset( pTmp, 0, sizeof( BTREE_INDEX_LEAF ) );
    return pTmp;
}

template <class RECTYPE>
void CMXBTree<RECTYPE>::DeleteIndexLeaf( BTREE_INDEX_LEAF * pPtr )
{
    m_nDelIndexLeaf ++;
    if( pPtr ) delete pPtr;
}

//申请一个新的数据叶
//如果不够内存,返回 NULL 
template <class RECTYPE>
CMXBTree<RECTYPE>::BTREE_DATA_LEAF *CMXBTree<RECTYPE>::NewDataLeaf( void )
{
    BTREE_DATA_LEAF *pTmp = new BTREE_DATA_LEAF;
    if ( !pTmp ) return NULL;

    m_nNewDataLeaf ++;

    memset( pTmp, 0, sizeof( BTREE_DATA_LEAF ) );
    return pTmp;
}

template <class RECTYPE>
void CMXBTree<RECTYPE>::DeleteDataLeaf( BTREE_DATA_LEAF * pPtr )
{
    m_nDelDataLeaf ++;
    if( pPtr ) delete pPtr;
}

//申请一个新的 DataContainer
//如果不够内存,返回 NULL 
template <class RECTYPE>
CMXBTree<RECTYPE>::DATA_CONTAINER *CMXBTree<RECTYPE>::NewDataContainer( void )
{
    DATA_CONTAINER *pTmp = new DATA_CONTAINER;
    if ( !pTmp ) return NULL;
    
    m_nNewDataCon ++;

    memset( pTmp, 0, sizeof( DATA_CONTAINER ) );
    return pTmp;
}

template <class RECTYPE>
void CMXBTree<RECTYPE>::DeleteDataContainer( DATA_CONTAINER *pPtr )
{

    m_nDelDataCon ++;
    if( pPtr ) delete pPtr;
}

//申请一个新的 RECTYPE
//如果不够内存,返回 NULL
template <class RECTYPE>
RECTYPE *CMXBTree<RECTYPE>::NewRecType( void )
{
    RECTYPE *pTmp = new RECTYPE;
    if ( !pTmp ) return NULL;

    m_nNewRecType ++;
    
    //memset( pTmp, 0, sizeof( RECTYPE ) );
    return pTmp;
}

template <class RECTYPE>
void CMXBTree<RECTYPE>::DeleteRecType( RECTYPE *pPtr )
{

    m_nDelRecType ++;
    if( pPtr ) delete pPtr;
}

//数据叶是否还有空位
//如果有空位则返回空位的位置 0 ~ BTREE_DEGREE - 1
//否则 返回 -1
template <class RECTYPE>
int CMXBTree<RECTYPE>::GetFreeElemInDataLeaf( BTREE_DATA_LEAF *pDataLeaf )
{
    for ( int i = 0 ; i < BTREE_DEGREE ; i++ )
    {
        if ( ! pDataLeaf->pDataCont[i] ) return i;
    }
    return -1;
}

//数据叶存放了多少元素
//返回值 0 ~ BTREE_DEGREE
template <class RECTYPE>
int CMXBTree<RECTYPE>::GetTotalElemInDataLeaf( BTREE_DATA_LEAF *pDataLeaf )
{
    for ( int i = 0 ; i < BTREE_DEGREE ; i++ )
    {
        if ( ! pDataLeaf->pDataCont[i] ) return i;
    }
    return BTREE_DEGREE;
}

//索引叶是否还有空位
//如果有空位则返回空位的位置 0 ~ BTREE_DEGREE - 1
//否则 返回 -1
template <class RECTYPE>
int CMXBTree<RECTYPE>::GetFreeElemInIndexLeaf( BTREE_INDEX_LEAF *pIndexLeaf )
{
    for ( int i = 0 ; i < BTREE_DEGREE ; i++ )
    {
        if ( ! (pIndexLeaf->IndexKeys[i].pKey) ) return i;
    }
    return -1;
}

//索引叶存放了多少元素
//返回值 0 ~ BTREE_DEGREE
template <class RECTYPE>
int CMXBTree<RECTYPE>::GetTotalElemInIndexLeaf( BTREE_INDEX_LEAF *pIndexLeaf )
{
    for ( int i = 0 ; i < BTREE_DEGREE ; i++ )
    {
        if ( ! (pIndexLeaf->IndexKeys[i].pKey) ) return i;
    }
    return BTREE_DEGREE;
}

//在索引叶中寻找可以插入Key的缝隙
//返回 0 ~ DEGREE 表示缝隙的位置
//返回 -1 表示B+Tree Error
template <class RECTYPE>
int CMXBTree<RECTYPE>::SeekInsertPoint( BTREE_INDEX_LEAF * pSearchIndexLeaf, RECTYPE & Key, bool *pKeyInIndex)
{
    if( pSearchIndexLeaf == NULL ) return -1;

    int i;
    int nLo = 0 , nHi = BTREE_DEGREE;
    
    while( true )
    {
        i = (nLo + nHi )/2;
        if( i == nLo && i == nHi ) return i; //发现了
        if( i == 0) //到了最左边
        {
            if( ! pSearchIndexLeaf->IndexKeys[0].pKey ) return -1;
            if( Key < *(pSearchIndexLeaf->IndexKeys[0].pKey) )
                return i;
            else 
            {
                nLo = i + 1;
                continue;
            }
        }
        //如果左边的元素空或者小于 Key
        if( !pSearchIndexLeaf->IndexKeys[i-1].pKey || Key < *(pSearchIndexLeaf->IndexKeys[i-1].pKey) )
        {
            nHi = i - 1;
            continue;
        }
        else
        if( pSearchIndexLeaf->IndexKeys[i].pKey ) //右边有元素
        {
            if( *(pSearchIndexLeaf->IndexKeys[i].pKey) < Key ) //比右边的元素大一点
            {
                nLo = i +1;
                continue;
            }
            else
            if( Key < *(pSearchIndexLeaf->IndexKeys[i].pKey) ) //比右边的元素小一点
                return i;
            else 
            {
                if( pKeyInIndex )
                    *pKeyInIndex = true;
                return i + 1;
            }
        }
        else //右边没有元素存在
            return i;
    }
    //return -1;
}

//取得可以存放 Key 的数据叶
//返回数据叶的索引叶的缝隙
//返回 -1 表示B+Tree 出错
template <class RECTYPE>
int CMXBTree<RECTYPE>::GetDataLeaf( RECTYPE &Key, BTREE_INDEX_LEAF * &pSearchIndexLeaf, BTREE_DATA_LEAF  * &pSearchDataLeaf, bool *pKeyInIndex )
{
    int i;
  
    //int nLo = 0 , nHi = BTREE_DEGREE;  
    while( true ) //一直循环
    {
        if( !pSearchIndexLeaf ) 
            return -1;
        if( pKeyInIndex && *pKeyInIndex )
            i = 0;
        else
            i = SeekInsertPoint( pSearchIndexLeaf, Key, pKeyInIndex); //查询插入位置
        if( i < 0 ) 
            return -1;
        void *pTmp;
        if( i == 0 )
            pTmp = pSearchIndexLeaf->pLeafLeft;
        else pTmp = pSearchIndexLeaf->IndexKeys[i-1].pKeyRight;

        if( pSearchIndexLeaf->cPointerType == DATA_LEAF_POINTER) //如果下面就是数据叶
        {
            pSearchDataLeaf = (BTREE_DATA_LEAF*)pTmp;
            return i;
        }
        else
        if( pSearchIndexLeaf->cPointerType == INDEX_LEAF_POINTER) //如果下面是索引叶
        {
            if( !pTmp ) 
                return -1;
            BTREE_INDEX_LEAF* pTmp2 = pSearchIndexLeaf;
            pSearchIndexLeaf = (BTREE_INDEX_LEAF*)pTmp;  //继续找下一个
            pSearchIndexLeaf->pParent = pTmp2;
            continue;            
        }
    }
}

//查找索引叶在父节点的位置
template <class RECTYPE>
int CMXBTree<RECTYPE>::SeekParent( BTREE_INDEX_LEAF * pParentLeaf, BTREE_INDEX_LEAF * pIndexLeaf)
{
    if ( pIndexLeaf == pParentLeaf->pLeafLeft ) return 0;
    else
    {
        int l;
        for( l = 0; l < BTREE_DEGREE; l ++ )
        {
            if( pIndexLeaf == pParentLeaf->IndexKeys[l].pKeyRight )
                return l + 1;
        }
        //寻找不到,BTREE 错误
        if ( l == BTREE_DEGREE ) 
            return -1;
    }
    return -1;
}

//分裂索引叶
//这个函数被 InsertKey 调用,
//调用背景是在数据叶的索引叶满了之后,
//需要对索引叶进行分裂
template <class RECTYPE>
int CMXBTree<RECTYPE>::SplitIndexLeaf(BTREE_INDEX_LEAF * pCurIndexLeaf, //要容纳新 Key 的索引叶
                    INDEX_KEY NewKey,       //新的 Key
                    int i )                 //插入位置 0 ~ BTREE_DEGREE
{
    INDEX_KEY TmpIndexKeys[BTREE_DEGREE + 1]; //能容纳所有 Key 的临时变量
    int j;    
    int l;

SplitAgain:

    memcpy(TmpIndexKeys, pCurIndexLeaf->IndexKeys, BTREE_DEGREE * sizeof( INDEX_KEY ));

    for( l = BTREE_DEGREE; l > i; l-- )
    {
        TmpIndexKeys[l] = TmpIndexKeys[l-1];
    }
    TmpIndexKeys[i] = NewKey;

    //如果自己就是根
    if ( !pCurIndexLeaf->pParent )
    {

        //新增两个索引叶
        BTREE_INDEX_LEAF *pIndexLeaf1 = NewIndexLeaf();
        if( !pIndexLeaf1 ) return -2;

        BTREE_INDEX_LEAF *pIndexLeaf2 = NewIndexLeaf();
        if( !pIndexLeaf2 ) return -2;

        int nCutPosition = (BTREE_DEGREE + 1)/2;
        
        //给这两个索引叶赋值
        for(l = 0 ; l < nCutPosition; l ++)
        {
            pIndexLeaf1->IndexKeys[l] = TmpIndexKeys[l] ;
        }

        pIndexLeaf1->pLeafLeft = pCurIndexLeaf->pLeafLeft;
        pIndexLeaf1->cPointerType = pCurIndexLeaf->cPointerType;
        pIndexLeaf1->pParent = pCurIndexLeaf;

        for(l = nCutPosition + 1,j = 0 ; l < BTREE_DEGREE+1; l ++, j++)
        {
            pIndexLeaf2->IndexKeys[j] = TmpIndexKeys[l] ;
        }
        pIndexLeaf2->pLeafLeft = TmpIndexKeys[nCutPosition].pKeyRight;
        pIndexLeaf2->cPointerType = pCurIndexLeaf->cPointerType;
        pIndexLeaf2->pParent = pCurIndexLeaf;
        
        //清空根的索引叶
        memset(pCurIndexLeaf->IndexKeys, 0, BTREE_DEGREE * sizeof( INDEX_KEY ));
        pCurIndexLeaf->IndexKeys[0].pKey = TmpIndexKeys[nCutPosition].pKey;
        pCurIndexLeaf->IndexKeys[0].pKeyRight = pIndexLeaf2;
        pCurIndexLeaf->pLeafLeft = pIndexLeaf1;

        //最后才设置 POINTER TYPE
        pCurIndexLeaf->cPointerType = INDEX_LEAF_POINTER;    
        return 0;
    }
    else
    //父节点存在
    {
        int nIndexLoc;

        //寻找 pCurIndexLeaf 在父节点的位置
        BTREE_INDEX_LEAF *pParentIndex = pCurIndexLeaf->pParent;
        nIndexLoc = SeekParent( pParentIndex, pCurIndexLeaf);
        if( nIndexLoc < 0 ) 
            return -1;

        if ( nIndexLoc < BTREE_DEGREE ) //往右看有没有兄弟有空
        {
            
            BTREE_INDEX_LEAF *pIndexLeaf;
            //右边有没有兄弟存在
            if ( pParentIndex->IndexKeys[nIndexLoc].pKey )
            {
                //将右边的兄弟取下来
                pIndexLeaf = (BTREE_INDEX_LEAF *)pParentIndex->IndexKeys[nIndexLoc].pKeyRight;
                if ( ! pIndexLeaf ) 
                    return -1;
                int nIndexLeafLoc = GetFreeElemInIndexLeaf( pIndexLeaf );
                //右边的兄弟有空
                if ( nIndexLeafLoc > -1 )
                {
                    //挤出空间出来
                    for ( j = nIndexLeafLoc; j > 0; j--)
                    {
                        pIndexLeaf->IndexKeys[j] = pIndexLeaf->IndexKeys[j-1];
                    }
                    pIndexLeaf->IndexKeys[0].pKey = pParentIndex->IndexKeys[nIndexLoc].pKey;
                    pIndexLeaf->IndexKeys[0].pKeyRight = pIndexLeaf->pLeafLeft;
                    pIndexLeaf->pLeafLeft = TmpIndexKeys[BTREE_DEGREE].pKeyRight;
                    pParentIndex->IndexKeys[nIndexLoc].pKey = TmpIndexKeys[BTREE_DEGREE].pKey ;
                    pParentIndex->IndexKeys[nIndexLoc].pKeyRight = pIndexLeaf;
                    memcpy(pCurIndexLeaf->IndexKeys, TmpIndexKeys, BTREE_DEGREE * sizeof( INDEX_KEY ));

                    return 0;
                }
            }
        }
        if ( nIndexLoc > 0 ) //看看左边的索引叶
        {
            BTREE_INDEX_LEAF *pParentIndex = pCurIndexLeaf->pParent;
            BTREE_INDEX_LEAF *pIndexLeaf;
            if ( nIndexLoc == 1)
            {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -