B+Tree模板改进版0.51版——可独立编译,修改了错误

       最近应网友的要求,仔细检查和修改了B+Tree的模板类,修正了几处错误,主要是删除Key的参数错误,同时去掉了那个头文件的包含,直接将头文件的内容贴在了文件开头处,以使此模板类可以独立使用。

       注释掉的显示到树控件中的方法,可以在使用MFC的CTreeCtrl情况下自行恢复即可,这样就可以将整个B+Tree显示到树控件中,方便只管的观察B+Tree节点的构造。但是因为B+Tree结构的特殊性,所以在查看时可能需要花些心思来分析。

#include <tchar.h>
#define WIN32_LEAN_AND_MEAN //在windows.h中排除单独引用的APIs,比如WinSock的API
#include <windows.h>
#pragma once
#define GRSPOSITION void*
//==========================================================
//TRank 表示每个节点中的阶数,则节点中的Key数目是2*TRank
//指向下级的指针数目是 2*TRank + 1,同时Key和Data是一对一的
//要求Key类型必须有 > 运算符
//实际使用中最好为TKey和TData类型重载 = 运算符
//==========================================================
template <class TKey,class TData,INT TRank>
class CGRSBTreeNode
{
public:
    INT m_nCnt;    //当前节点中的Key个数
    TKey  m_Key [2 * TRank]; //Key数组
    TData m_Data[2 * TRank];    //Data数组

    CGRSBTreeNode<TKey,TData,TRank>* m_pChild[ 2 * TRank + 1 ]; //指向孩子的指针数组
public:
    CGRSBTreeNode()
        :m_nCnt(0)
    {
        ::ZeroMemory(m_Key, 2 * TRank * sizeof(TKey));
        ::ZeroMemory(m_Data,2 * TRank * sizeof(TData));
        ::ZeroMemory(m_pChild,( 2 * TRank + 1) * sizeof(CGRSBTreeNode<TKey,TData,TRank>*));
    }
};


template <class TKey,class TData,INT TRank = 10>
class CGRSBTree
{
protected:
    CGRSBTreeNode<TKey,TData,TRank>* m_pRoot; //树根节点
    INT  m_iHeight;        //树高度
    INT m_nKeyCnt;        //键总数
    INT m_nNodeCnt;       //节点总数
protected:
    INT m_nSearchIndex;       // 查找时找到的键在节点中的位置

    TData m_InsData;        // 与要插的键相对应的值
    TKey m_InsKey;        /// 要插入的键

    INT  m_iAccessLevel;       // 当前访问的节点所处的高度
    CGRSBTreeNode<TKey,TData,TRank>* m_pNewNode; // 在节点分割的时候指向新建的节点

    BOOL m_bFlag;         // 节点增减标志
public:
    CGRSBTree()
        :m_iHeight(0)
        ,m_nKeyCnt(0)
        ,m_nNodeCnt(0)
        ,m_nSearchIndex(0)
        ,m_iAccessLevel(0)
        ,m_pNewNode(NULL)
        ,m_bFlag(FALSE)
    {
        //申请一个0节点的树根
        m_pRoot = NULL;
    }

    virtual ~CGRSBTree()
    {
    }

protected:
    void Insert(CGRSBTreeNode<TKey,TData,TRank>*& pNode,const TKey& Key,const TData& Data)
    {
        INT i = 0;
        INT j = 0;
        INT k = 0;

        m_iAccessLevel --;

        if ( m_iAccessLevel < 0 )
        {
            m_pNewNode = NULL;
            m_InsKey = Key;
            m_InsData = Data;
            m_nKeyCnt ++;
            m_bFlag = TRUE;
            //pNode = NewNode(pNode,Key,Data);
            return;
        }


        for(i = 0, j = pNode->m_nCnt - 1;
            i < j;
            k= ( j + i) / 2, ( Key > pNode-> m_Key[k])?( i = k + 1 ):( j = k ));

        if ( Key == pNode-> m_Key[ i ] )
        {
            Error(1,Key); /* 键已经在树中 */
            m_bFlag = FALSE;
            return;
        }

        if ( Key > pNode-> m_Key[ i ] )
        {/* i == pNode->m_nCnt - 1 时有可能出现 */
            i ++;
        }

        //向孩子节点插入
        Insert( pNode -> m_pChild[ i ] , Key, Data );

        if ( FALSE == m_bFlag )
        {
            return;
        }

        /* 有新键要插入到当前节点中 */
        if ( pNode->m_nCnt < 2 * TRank )
        {/* 当前节点未满 */
            InsertAt( pNode, i ,Key,Data); /* 把键值+子树对插入当前节点中 */
            m_bFlag = FALSE; /* 指示上层节点没有需要插入的键值+子树,插入过程结束 */
        }
        else
        {/* 当前节点已满,则分割这个页面并把键值+子树对插入当前节点中 */
            SplitNode(pNode, i); /* 继续指示上层节点把返回的键值+子树插入其中 */
        }
    }

    /*
    * 把一个键和对应的右子树插入一个节点中
    */
    void InsertAt(CGRSBTreeNode<TKey,TData,TRank>* pNode, INT nIndex,const TKey& Key,const TData& Data)
    {
        int i = 0;
        /* 把所有大于要插入的键值的键和对应的右子树右移 */
        for(i = pNode->m_nCnt; i > nIndex; i--)
        {
            pNode-> m_Key[ i ]  = pNode-> m_Key[i-1];
            pNode-> m_Data[ i ]  = pNode-> m_Data[i-1];
            pNode-> m_pChild[i+1] = pNode-> m_pChild[ i ];
        }

        /* 插入键和右子树 */
        pNode-> m_Key[ i ]  = Key;
        pNode-> m_Data[ i ]  = Data;
        pNode-> m_pChild[ i + 1 ] = m_pNewNode;
        pNode-> m_nCnt ++;
    }

    /*
    * 前件是要插入一个键和对应的右子树,并且本节点已经满
    * 导致分割这个节点,插入键和对应的右子树,
    * 并向上层返回一个要插入键和对应的右子树
    */
    void SplitNode( CGRSBTreeNode<TKey,TData,TRank>*& pNode, INT nIndex )
    {    
        INT i = 0;
        INT j = 0;
        CGRSBTreeNode<TKey,TData,TRank>* pTmpNode = NULL;
        TKey tmpKey;
        TData tmpData;
        /* 建立新节点 */
        pTmpNode = new CGRSBTreeNode<TKey,TData,TRank>();
        /*
        *   +---+--------+-----------+---------+--------+---------+
        *   | 0 | ...... |  TRank    | TRank+1 | ...... |2*TRank-1|
        *   +---+--------+-----------+---------+--------+---------+
        *   |<-      TRank+1       ->|<-        TRank-1         ->|  
        */

        if ( nIndex > TRank )
        {//要插入当前节点的右半部分
            //把从 2*TRank-1 到 TRank+1 的 TRank-1 个键值+子树对转移到新节点中,
            //并且为要插入的键值+子树空出位置
            for( i = 2 * TRank - 1, j = TRank - 1; i >= nIndex; i --,j --)
            {
                pTmpNode-> m_Key[j]    = pNode-> m_Key[ i ];
                pTmpNode-> m_Data[j]   = pNode-> m_Data[ i ];
                pTmpNode-> m_pChild[ j + 1 ] = pNode-> m_pChild[i + 1];
            }

            for(i = nIndex - 1, j = nIndex - TRank - 2; j >= 0; i--,j--)
            {
                pTmpNode-> m_Key[j]    = pNode-> m_Key[ i ];
                pTmpNode-> m_Data[j]   = pNode-> m_Data[ i ];
                pTmpNode-> m_pChild[ j + 1 ] = pNode-> m_pChild[i + 1];
            }

            //把节点的最右子树转移成新节点的最左子树
            pTmpNode-> m_pChild[0] = pNode-> m_pChild[ TRank + 1 ];

            //在新节点中插入键和右子树
            pTmpNode-> m_Key[ nIndex - TRank - 1] = m_InsKey;
            pTmpNode-> m_Data[ nIndex - TRank - 1] = m_InsData;
            pTmpNode-> m_pChild[ nIndex - TRank ] = m_pNewNode;

            //设置要插入上层节点的键和值
            m_InsKey = pNode-> m_Key[TRank];
            m_InsData = pNode-> m_Data[TRank];

            //tmpKey  = pNode->m_Key[TRank];
            //tmpData = pNode->m_Data[TRank];
        }
        else
        { /* nIndex <= TRank */
            /* 把从 2*TRank-1 到 TRank 的 TRank 个键值+子树对转移到新节点中 */
            for( i = 2 * TRank - 1,j = TRank - 1; j >= 0; i--,j--)
            {
                pTmpNode-> m_Key[j]   = pNode-> m_Key[ i ];
                pTmpNode-> m_Data[j]  = pNode-> m_Data[ i ];
                pTmpNode-> m_pChild[j + 1] = pNode-> m_pChild[ i + 1 ];
            }

            if (nIndex == TRank)
            {
                pTmpNode-> m_pChild[0] = m_pNewNode;
            }
            else
            { /* (nIndex<TRank) 要插入当前节点的左半部分 */
                /* 把节点当前的最右子树转移成新节点的最左子树 */
                pTmpNode-> m_pChild[0] = pNode-> m_pChild[ TRank ];
                /* 保存要插入上层节点的键和值 */
                tmpKey = pNode-> m_Key[ TRank - 1];
                tmpData = pNode-> m_Data[ TRank - 1];

                /* 把所有大于要插入的键值的键和对应的右子树右移 */
                for(i = TRank - 1; i > nIndex; i --)
                {
                    pNode-> m_Key[ i ]   = pNode-> m_Key[i-1];
                    pNode-> m_Data[ i ]   = pNode-> m_Data[i - 1];
                    pNode-> m_pChild[ i + 1 ] = pNode-> m_pChild[ i ];
                }

                pNode-> m_Key[nIndex]  = m_InsKey;
                pNode-> m_Data[nIndex]  = m_InsData;

                pNode-> m_pChild[nIndex+1] = m_pNewNode;

                m_InsKey = tmpKey;
                m_InsData = tmpData;
            }
        }

        pNode->m_nCnt = TRank;
        pTmpNode->m_nCnt= TRank;
        m_pNewNode  = pTmpNode;
        m_nNodeCnt ++;

        //pNode = NewNode(pNode,tmpKey,tmpData);
    }


    void Remove( CGRSBTreeNode<TKey,TData,TRank>* pNode,const TKey& Key,TData& Data)
    {
        INT i = 0;
        INT j = 0;
        INT k = 0;
        CGRSBTreeNode<TKey,TData,TRank>* pLeft = NULL;
        CGRSBTreeNode<TKey,TData,TRank>* pRight = NULL;
        INT nTmpLevel = 0;

        m_iAccessLevel -- ;

        if ( m_iAccessLevel < 0 )
        {
            Error(0,Key); /* 在整个树中未找到要删除的键 */
            m_bFlag = FALSE;
            return;
        }

        for(i=0, j = pNode->m_nCnt - 1;
            i < j;
            k=( j + i ) / 2, ( Key > pNode-> m_Key[k] ) ? (i = k + 1):( j = k ));

        if ( Key == pNode-> m_Key[ i ] )
        { /* 找到要删除的键 */
            Data = pNode-> m_Data[ i ];

            if (m_iAccessLevel == 0)
            { 
                DelFromNode(pNode,i);

                m_nKeyCnt -- ;
                m_bFlag = TRUE;
                return;
            }
            else
            { /* 这个键位于非叶节点 */
                nTmpLevel = m_iAccessLevel - 1;

                /* 找到前驱节点 */
                pRight = pNode-> m_pChild[ i ];

                while (nTmpLevel > 0) 
                {
                    pRight = pRight->m_pChild[pRight->m_nCnt];
                    nTmpLevel--;
                }

                pNode-> m_Key[ i ]  = pRight-> m_Key[pRight->m_nCnt-1];
                pNode-> m_Data[ i ]  = pRight-> m_Data[pRight->m_nCnt-1];
                pRight-> m_Data[pRight->m_nCnt-1] = NULL;
                //Key = pRight-> m_Key[ pRight->m_nCnt - 1 ];
            }
        }
        else if (Key > pNode-> m_Key[ i ])
        {/* i == pNode->m_nCnt-1 时有可能出现 */
            i++;         
        }

        Remove(pNode-> m_pChild[ i ], Key , Data );

        /* 调整平衡 */
        if ( FALSE == m_bFlag )
        {
            return;
        }

        if (pNode-> m_pChild[ i ]->m_nCnt < TRank)
        {
            if (i == pNode->m_nCnt)
            {/* 在最右子树中发生了删除 */
                i--; /* 调整最右键的左右子树平衡 */
            }

            pLeft = pNode-> m_pChild [ i ];
            pRight = pNode-> m_pChild[i+1];

            if (pRight->m_nCnt > TRank)
            {
                MoveLeftNode(pNode,i);
            }
            else if(pLeft->m_nCnt > TRank)
            {
                MoveRightNode(pNode,i);
            }
            else
            {
                JoinNode(pNode,i);
                /* 继续指示上层节点本子树的键数量减少 */
                return;
            }

            m_bFlag = FALSE;
            /* 指示上层节点本子树的键数量没有减少,删除过程结束 */
        }
    }

    /*
    * 合并一个节点的某个键对应的两个子树
    */
    void JoinNode(CGRSBTreeNode<TKey,TData,TRank>* pNode, INT nIndex)
    {
        CGRSBTreeNode<TKey,TData,TRank>* pLeft = NULL;
        CGRSBTreeNode<TKey,TData,TRank>* pRight = NULL;
        INT i = 0;
        INT j = 0;

        pLeft = pNode-> m_pChild[nIndex];
        pRight = pNode-> m_pChild[nIndex + 1];

        /* 把这个键下移到它的左子树 */
        pLeft-> m_Key[pLeft->m_nCnt] = pNode-> m_Key[nIndex];
        pLeft-> m_Data[pLeft->m_nCnt] = pNode-> m_Data[nIndex];

        /* 把右子树中的所有键值和子树转移到左子树 */
        for (j=pRight->m_nCnt-1,i=pLeft->m_nCnt+pRight->m_nCnt; j >= 0 ; j--,i--)
        {
            pLeft-> m_Key[ i ]  = pRight-> m_Key[j];
            pLeft-> m_Data[ i ]  = pRight-> m_Data[j];
            pLeft-> m_pChild[ i ] = pRight-> m_pChild[j];
        }

        pLeft-> m_pChild[ pLeft->m_nCnt + pRight->m_nCnt + 1 ] = pRight-> m_pChild[ pRight->m_nCnt ];
        pLeft->m_nCnt += pRight->m_nCnt + 1;

        delete pRight;
        /* 把这个键右边的键和对应的右子树左移 */
        for (i=nIndex; i < pNode->m_nCnt-1; i++)
        {
            pNode-> m_Key[ i ] = pNode-> m_Key[i+1];
            pNode-> m_Data[ i ] = pNode-> m_Data[i+1];
            pNode-> m_pChild[i+1] = pNode-> m_pChild[i+2];
        }

        pNode->m_nCnt --;
        m_nNodeCnt --;
    }

    /*
    * 从一个键的右子树向左子树转移一些键,使两个子树平衡
    */

    void MoveLeftNode(CGRSBTreeNode<TKey,TData,TRank>* pNode, INT nIndex)
    {
        CGRSBTreeNode<TKey,TData,TRank>* pLeft = NULL;
        CGRSBTreeNode<TKey,TData,TRank>* pRight = NULL;

        INT k = 0; /* 应转移的键的数目 */
        INT i = 0;
        INT j = 0;

        pLeft  = pNode-> m_pChild[nIndex];
        pRight = pNode-> m_pChild[nIndex + 1];

        k = ( pRight->m_nCnt - pLeft->m_nCnt ) / 2;

        /* 把这个键下移到它的左子树 */
        pLeft-> m_Key[pLeft->m_nCnt] = pNode-> m_Key[nIndex];
        pLeft-> m_Data[pLeft->m_nCnt] = pNode-> m_Data[nIndex];

        /* 把右子树的最左子树转移成左子树的最右子树
        * 从右子树向左子树移动 k-1 个键+子树对 */
        for (j=k-2,i=pLeft->m_nCnt+k-1; j >= 0; j--,i--)
        {
            pLeft-> m_Key[ i ]  = pRight-> m_Key[j];
            pLeft-> m_Data[ i ]  = pRight-> m_Data[j];
            pLeft-> m_pChild[ i ] = pRight-> m_pChild[j];
        }

        pLeft-> m_pChild[ pLeft->m_nCnt + k ] = pRight-> m_pChild[ k - 1 ];

        /* 把右子树的最左键提升到这个键的位置上 */
        pNode-> m_Key[nIndex] = pRight-> m_Key[k-1];
        pNode-> m_Data[nIndex] = pRight-> m_Data[k-1];

        /* 把右子树中的所有键值和子树左移 k 个位置 */
        pRight-> m_pChild[0] = pRight-> m_pChild[k];

        for (i=0; i<pRight->m_nCnt-k; i++)
        {
            pRight-> m_Key[ i ]  = pRight-> m_Key[ i + k ];
            pRight-> m_Data[ i ] = pRight-> m_Data[ i + k ];
            pRight-> m_pChild[ i ] = pRight-> m_pChild[ i + k ];
        }

        pRight-> m_pChild[ pRight->m_nCnt - k ] = pRight-> m_pChild[pRight->m_nCnt];
        pLeft->m_nCnt += k;
        pRight->m_nCnt -= k;
    }

    /*
    * 从一个键的左子树向右子树转移一些键,使两个子树平衡
    */

    void MoveRightNode( CGRSBTreeNode<TKey,TData,TRank>* pNode, INT nIndex)
    {
        CGRSBTreeNode<TKey,TData,TRank>* pLeft = NULL;
        CGRSBTreeNode<TKey,TData,TRank>* pRight = NULL;

        INT k = 0; /* 应转移的键的数目 */
        INT i = 0;
        INT j = 0;

        pLeft = pNode-> m_pChild[nIndex];
        pRight = pNode-> m_pChild[nIndex + 1];

        k = ( pLeft->m_nCnt - pRight->m_nCnt ) / 2;

        /* 把右子树中的所有键值和子树右移 k 个位置 */
        pRight-> m_pChild[ pRight->m_nCnt + k ] = pRight-> m_pChild[ pRight->m_nCnt ];

        for ( i = pRight->m_nCnt - 1; i >= 0; i -- )
        {
            pRight-> m_Key[i + k]  = pRight-> m_Key[ i ];
            pRight-> m_Data[i + k]  = pRight-> m_Data[ i ];
            pRight-> m_pChild[ i + k ] = pRight-> m_pChild[ i ];
        }

        /* 把这个键下移到它的右子树 */
        pRight-> m_Key[k - 1] = pNode-> m_Key[nIndex];
        pRight-> m_Data[k - 1] = pNode-> m_Data[nIndex];

        /* 把左子树的最右子树转移成右子树的最左子树 */

        pRight-> m_pChild[k-1] = pLeft-> m_pChild[pLeft->m_nCnt];

        /* 从左子树向右子树移动 k-1 个键+子树对 */
        for ( i = pLeft->m_nCnt - 1,j = k - 2; j >= 0; j --,i -- )
        {
            pRight-> m_Key[j]  = pLeft-> m_Key[ i ];
            pRight-> m_Data[j]  = pLeft-> m_Data[ i ];
            pRight-> m_pChild[j] = pLeft-> m_pChild[ i ];
        }

        /* 把左子树的最右键提升到这个键的位置上 */
        pNode-> m_Key[nIndex] = pLeft-> m_Key[ i ];
        pNode-> m_Data[nIndex] = pLeft-> m_Data[ i ];
        pLeft->m_nCnt -= k;
        pRight->m_nCnt += k;
    }

    /*
    * 把一个键和对应的右子树从一个节点中删除
    */
    void DelFromNode(CGRSBTreeNode<TKey,TData,TRank>* pNode, INT nIndex)
    {
        INT i = 0;
        /* 把所有大于要删除的键值的键左移 */
        for( i = nIndex; i < pNode->m_nCnt - 1; i ++ )
        {
            pNode-> m_Key[ i ] = pNode-> m_Key[i+1];
            pNode-> m_Data[ i ] = pNode-> m_Data[i+1];
        }

        pNode->m_nCnt --;
    }

    /*
    * 建立有两个子树和一个键的根节点
    */

    CGRSBTreeNode<TKey,TData,TRank>* NewNode(CGRSBTreeNode<TKey,TData,TRank>* pNode,const TKey& Key,const TData& Data)
    {
        CGRSBTreeNode<TKey,TData,TRank>* pTmpNode = NULL;
        pTmpNode = new CGRSBTreeNode<TKey,TData,TRank>();
        pTmpNode-> m_nCnt = 1;
        pTmpNode-> m_pChild[0] = pNode;
        pTmpNode-> m_pChild[1] = m_pNewNode;
        pTmpNode-> m_Key[0]    = Key;
        pTmpNode-> m_Data[0]   = Data;
        m_iHeight ++;
        m_nNodeCnt ++;

        return( pTmpNode );
    }

    /*
    * 释放根节点,并返回它的最左子树
    */
    CGRSBTreeNode<TKey,TData,TRank>* FreeNode(CGRSBTreeNode<TKey,TData,TRank>* pNode)
    {
        CGRSBTreeNode<TKey,TData,TRank>* pTmpNode = pNode-> m_pChild[0];
        delete pNode;
        m_iHeight --;
        m_nNodeCnt --;
        return pTmpNode;
    }

    void Error(int f,TKey Key)
    {
        //自定义的出错处理代码
    }

 

    void DelAll(CGRSBTreeNode<TKey,TData,TRank>* pNode)
    {
        INT i = 0;
        m_iAccessLevel --;

        if ( m_iAccessLevel > 0 )
        {
            for ( i = 0; i <= pNode->m_nCnt ; i ++ )
            {
                DelAll( pNode-> m_pChild[ i ] );
            }
        }

        delete pNode;

    }
public:
    BOOL Add(const TKey& Key,const TData& Data)
    {
        m_iAccessLevel = m_iHeight;

        Insert( m_pRoot, Key, Data );

        if ( m_bFlag )
        {
            m_pRoot = NewNode(m_pRoot,Key,Data);    /* 树的高度增加 */
        }

        return TRUE;
    }

    BOOL Del( const TKey& Key, TData& Data )
    {
        m_iAccessLevel = m_iHeight;

        Remove( m_pRoot, Key, Data );

        if ( 0 == m_pRoot->m_nCnt )
        {
            m_pRoot = FreeNode( m_pRoot );
        }

        return TRUE;
    }

    INT GetHeight()
    {
        return m_iHeight;
    }

    INT GetKeys()
    {
        return m_nKeyCnt;
    }

    double GetPayload()
    {
        if (m_nNodeCnt==0)
        {
            return 1;
        }
        return (double) m_nKeyCnt / (double)( m_nNodeCnt *( 2 * TRank ) );
    }

    CGRSBTreeNode<TKey,TData,TRank>* Destroy ()
    {    
        m_iAccessLevel = m_iHeight;
        m_iHeight      = 0;

        return Delall(m_pRoot);

    }
public:

    GRSPOSITION Search(const TKey& Key, TData& Data)
    {
        INT i = 0;
        INT j = 0;
        INT k = 0;

        INT nLevel = m_iHeight;

        CGRSBTreeNode<TKey,TData,TRank>* pNode = m_pRoot;

        while ( nLevel >= 0 )
        {
            for( i = 0, j = pNode->m_nCnt - 1;
                i < j;
                k = ( j + i ) / 2, ( Key > pNode->m_Key[ k ] ) ? ( i = k + 1) : ( j = k ) );

            if ( Key == pNode->m_Key [ i ] )
            {//找到
                Data = pNode->m_Data[i];
                return (GRSPOSITION) &pNode->m_Key[i];
            }

            if ( Key > pNode->m_Key [ i ] )
            {//节点在右侧
                i ++;
            }

            pNode = pNode->m_pChild[ i ];
            nLevel --; //到下层查找
        }

        return NULL;
    }

    CGRSBTreeNode<TKey,TData,TRank>* GetRoot()
    {
        return m_pRoot;
    }

    //void Show2Tree(CTreeCtrl*pTree,HTREEITEM hItem,CGRSBTreeNode<TKey,TData,TRank>*pNode)
    //{
    //    if( NULL == pNode )
    //    {
    //        return;
    //    }


    //    HTREEITEM hTmp = NULL;
    //    CString strTmp;

    //    for( INT i = 0; i < pNode->m_nCnt; i ++ )
    //    {
    //        if( 0 == i )
    //        {
    //            hTmp = pTree->InsertItem(_T("Child(Start)"),hItem);
    //            Show2Tree(pTree,hTmp,pNode->m_pChild[0]);
    //        }
    //        strTmp.Format(_T("Key(%d)"),pNode->m_Key[i]);

    //        hTmp = pTree->InsertItem(strTmp,hItem);
    //        Show2Tree(pTree,hTmp,pNode->m_pChild[i+1]);
    //    }
    //}

};


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GamebabyRockSun_QQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值