C++ 2-3树的插入

C++ 2-3树的插入

首先要定义23树的基本结构

typedef struct _23TreeNode {
    unsigned char   _kCount;
    int* _pV[3];
    _23TreeNode*    _pFather;
    _23TreeNode*    _pNextNode[4];
}_23TreeNode;

_23TreeNode* g_p23Tree = new _23TreeNode;

初始化23树节点的代码如下

void init23TreeNode(_23TreeNode* node)
{
    node->_kCount = 0;
    memset(node->_pV, 0, sizeof(node->_pV));
    node->_pFather = nullptr;
    memset(node->_pNextNode, 0, sizeof(node->_pNextNode));
}

_kCount表示23树节点key的数量
_pV表示23树节点的key值

23树的插入首先要确保可以正确的分解临时的4节点
我定义了一个宏用来交换两个PTR

#define SWAP_PTR(x, y)  {auto tmp = x; x = y; y = tmp;}

下面是插入节点的代码

void push23TreeNode(int key)
{
    //从头结点开始找
    _23TreeNode* p = g_p23Tree;
    while (p)
    {
        if (p->_pV[0] && key <= *p->_pV[0] && p->_pNextNode[0])
        {
            //左侧
            if (key == *p->_pV[0]) return;
            p = p->_pNextNode[0];
        }
        else if (p->_kCount >= 1 && p->_pV[p->_kCount - 1] && key >= *p->_pV[p->_kCount - 1] && p->_pNextNode[p->_kCount])
        {
            //右侧
            if (key == *p->_pV[p->_kCount - 1]) return;
            p = p->_pNextNode[p->_kCount];
        }
        else if (p->_kCount == 2 && p->_pNextNode[1])
        {
            //中间
            p = p->_pNextNode[1];
        }
        else
        {
            break;
        }
    }
    int* pValue = new int;
    *pValue = key;
    switch (p->_kCount)
    {
    case 0: //该节点为ROOT节点 直接插入该值
        p->_pV[p->_kCount++] = pValue;
        break;
    case 1: //该节点为2节点 直接插入该值
    {
        p->_pV[p->_kCount++] = pValue;
        //如果V1大于V2 则换位置
        if (*p->_pV[1] < *p->_pV[0])
        {
            SWAP_PTR(p->_pV[1], p->_pV[0]);
        }
        SWAP_PTR(p->_pNextNode[1], p->_pNextNode[2]);
        break;
    }
    case 2: //该节点为3节点 
    {
        //将值插入该节点中
        while (p)
        {
            p->_pV[p->_kCount] = pValue;
            ++p->_kCount;
            if (p->_kCount == 2)
            {
                //如果插入后 该节点是3节点 则移动指针并退出
                //如果当前插入的值比当前节点原来的值要小 则需要将两个值换位置
                if (*p->_pV[1] < *p->_pV[0])
                {
                    SWAP_PTR(p->_pV[1], p->_pV[0]);
                }
                break;
            }
            else
            {
                //插入后 该节点是4节点 则将中间值的指针赋值给pValue
                if (*pValue < *p->_pV[0])
                {
                    SWAP_PTR(pValue, p->_pV[0]);
                }
                else if (*pValue > * p->_pV[1])
                {
                    SWAP_PTR(pValue, p->_pV[1]);
                }

                //将4节点分解成两个2节点
                //当前新节点pNode为p的右侧
                _23TreeNode* pNode = new _23TreeNode;
                init23TreeNode(pNode);
                pNode->_kCount = 1;
                pNode->_pFather = p->_pFather;
                pNode->_pNextNode[0] = p->_pNextNode[2];
                pNode->_pNextNode[1] = p->_pNextNode[3];
                pNode->_pV[0] = p->_pV[1];
                p->_pV[1] = p->_pV[2] = nullptr;
                p->_pNextNode[2] = p->_pNextNode[3] = nullptr;
                p->_kCount = 1;


                //p在父节点中的下一个节点应为pNode
                if(p->_pFather)
                {
                    for (int i = 0; i <= p->_pFather->_kCount; ++i)
                    {
                        if (p->_pFather->_pNextNode[i] == p)
                        {
                            //后续所有节点往后移动一位
                            for (int j = p->_pFather->_kCount; j > i; --j)
                            {
                                p->_pFather->_pNextNode[j + 1] = p->_pFather->_pNextNode[j];
                            }
                            p->_pFather->_pNextNode[i + 1] = pNode;
                            p = p->_pFather;
                            break;
                        }
                    }
                }
                else
                {
                    //没有父节点 说明还需要创建一个父节点来连接p和pNode
                    _23TreeNode* pRoot = new _23TreeNode;
                    init23TreeNode(pRoot);
                    pRoot->_kCount = 1;
                    pRoot->_pV[0] = pValue;
                    pRoot->_pNextNode[0] = p;
                    pRoot->_pNextNode[1] = pNode;
                    p->_pFather = pNode->_pFather = pRoot;
                    SWAP_PTR(pRoot, g_p23Tree);
                    break;
                }
            }
        }
    }
    default:
        return;
    }
}

注意:
分解节点时 要将这个节点下属的4个_pNextNode分给分解后生成的两个节点
分解后 临时4节点会变成2个2节点 每个节点带有一个_pV值和两个_pNextNode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值