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