📄 cpp2.cpp
字号:
// 删除本结点
delete pBrother;
}
return DeleteInternalNode(pFather, NewKey);
}
// 清除整个树,删除所有结点
void BPlusTree::ClearTree()
{
CNode* pNode = GetRoot();
if (NULL != pNode)
{
pNode->DeleteChildren();
delete pNode;
}
m_pLeafHead = NULL;
m_pLeafTail = NULL;
SetRoot(NULL);
}
// 旋转以重新平衡,实际上是把整个树重构一下,结果不理想,待重新考虑
BPlusTree* BPlusTree::RotateTree()
{
BPlusTree* pNewTree = new BPlusTree;
int i = 0;
CLeafNode * pNode = m_pLeafHead;
while (NULL != pNode)
{
for (int i = 1; i <= pNode->GetCount(); i ++)
{
(void)pNewTree->Insert(pNode->GetElement(i));
}
pNode = pNode->m_pNextNode;
}
return pNewTree;
}
// 检查树是否满足B+树的定义
bool BPlusTree::CheckTree()
{
CLeafNode * pThisNode = m_pLeafHead;
CLeafNode * pNextNode = NULL;
while (NULL != pThisNode)
{
pNextNode = pThisNode->m_pNextNode;
if (NULL != pNextNode)
{
if (pThisNode->GetElement(pThisNode->GetCount()) > pNextNode->GetElement(1))
{
return false;
}
}
pThisNode = pNextNode;
}
return CheckNode(GetRoot());
}
// 递归检查结点及其子树是否满足B+树的定义
bool BPlusTree::CheckNode(CNode* pNode)
{
if (NULL == pNode)
{
return true;
}
int i = 0;
bool ret = false;
// 检查是否满足50%的填充度
if ((pNode->GetCount() < ORDER_V) && (pNode != GetRoot()))
{
return false;
}
// 检查键或数据是否按大小排序
for (i = 1; i < pNode->GetCount(); i++)
{
if (pNode->GetElement(i) > pNode->GetElement(i + 1))
{
return false;
}
}
if (NODE_TYPE_LEAF == pNode->GetType())
{
return true;
}
// 对中间结点,递归检查子树
for (i = 1; i <= pNode->GetCount() + 1; i++)
{
ret = CheckNode(pNode->GetPointer(i));
// 只要有一个不合法就返回不合法
if (false == ret)
{
return false;
}
}
return true;
}
// 打印整个树
void BPlusTree::PrintTree()
{
CNode* pRoot = GetRoot();
if (NULL == pRoot) return;
CNode* p1, *p2, *p3;
int i, j, k;
int total = 0;
printf("\n第一层\n | ");
PrintNode(pRoot);
total = 0;
printf("\n第二层\n | ");
for (i = 1; i <= MAXNUM_POINTER; i++)
{
p1 = pRoot->GetPointer(i);
if (NULL == p1) continue;
PrintNode(p1);
total++;
if (total%4 == 0) printf("\n | ");
}
total = 0;
printf("\n第三层\n | ");
for (i = 1; i <= MAXNUM_POINTER; i++)
{
p1 = pRoot->GetPointer(i);
if (NULL == p1) continue;
for (j = 1; j <= MAXNUM_POINTER; j++)
{
p2 = p1->GetPointer(j);
if (NULL == p2) continue;
PrintNode(p2);
total++;
if (total%4 == 0) printf("\n | ");
}
}
total = 0;
printf("\n第四层\n | ");
for (i = 1; i <= MAXNUM_POINTER; i++)
{
p1 = pRoot->GetPointer(i);
if (NULL == p1) continue;
for (j = 1; j <= MAXNUM_POINTER; j++)
{
p2 = p1->GetPointer(j);
if (NULL == p2) continue;
for (k = 1; k <= MAXNUM_POINTER; k++)
{
p3 = p2->GetPointer(k);
if (NULL == p3) continue;
PrintNode(p3);
total++;
if (total%4 == 0) printf("\n | ");
}
}
}
}
// 打印某结点
void BPlusTree::PrintNode(CNode* pNode)
{
if (NULL == pNode)
{
return;
}
for (int i = 1; i <= MAXNUM_KEY; i++)
{
printf("%3d ", pNode->GetElement(i));
if (i >= MAXNUM_KEY)
{
printf(" | ");
}
}
}
// 查找对应的叶子结点
CLeafNode* BPlusTree::SearchLeafNode(KEY_TYPE data)
{
int i = 0;
CNode * pNode = GetRoot();
// 循环查找对应的叶子结点
while (NULL != pNode)
{
// 结点为叶子结点,循环结束
if (NODE_TYPE_LEAF == pNode->GetType())
{
break;
}
// 找到第一个键值大于等于key的位置
for (i = 1; i <= pNode->GetCount(); i++)
{
if (data < pNode->GetElement(i))
{
break;
}
}
pNode = pNode->GetPointer(i);
}
return (CLeafNode*)pNode;
}
//递归函数:插入键到中间结点
bool BPlusTree::InsertInternalNode(CInternalNode* pNode, KEY_TYPE key, CNode* pRightSon)
{
if (NULL == pNode || NODE_TYPE_LEAF ==pNode->GetType())
{
return false;
}
// 结点未满,直接插入
if (pNode->GetCount() < MAXNUM_KEY)
{
return pNode->Insert(key, pRightSon);
}
CInternalNode* pBrother = new CInternalNode;
KEY_TYPE NewKey = INVALID;
// 分裂本结点
NewKey = pNode->Split(pBrother, key);
if (pNode->GetCount() < pBrother->GetCount())
{
pNode->Insert(key, pRightSon);
}
else if (pNode->GetCount() > pBrother->GetCount())
{
pBrother->Insert(key, pRightSon);
}
else // 两者相等,即键值在第V和V+1个键值中间的情况,把字节点挂到新结点的第一个指针上
{
pBrother->SetPointer(1,pRightSon);
pRightSon->SetFather(pBrother);
}
CInternalNode* pFather = (CInternalNode*)(pNode->GetFather());
// 直到根结点都满了,新生成根结点
if (NULL == pFather)
{
pFather = new CInternalNode;
pFather->SetPointer(1, pNode); // 指针1指向原结点
pFather->SetElement(1, NewKey); // 设置键
pFather->SetPointer(2, pBrother); // 指针2指向新结点
pNode->SetFather(pFather); // 指定父结点
pBrother->SetFather(pFather); // 指定父结点
pFather->SetCount(1);
SetRoot(pFather); // 指定新的根结点
return true;
}
// 递归
return InsertInternalNode(pFather, NewKey, pBrother);
}
// 递归函数:在中间结点中删除键
bool BPlusTree::DeleteInternalNode(CInternalNode* pNode, KEY_TYPE key)
{
// 删除键,如果失败一定是没有找到,直接返回失败
bool success = pNode->Delete(key);
if (false == success)
{
return false;
}
// 获取父结点
CInternalNode* pFather = (CInternalNode*)(pNode->GetFather());
if (NULL == pFather)
{
// 如果一个数据都没有了,把根结点的第一个结点作为根结点
if (0 == pNode->GetCount())
{
SetRoot(pNode->GetPointer(1));
delete pNode;
}
return true;
}
// 删除后结点填充度仍>=50%
if (pNode->GetCount() >= ORDER_V)
{
for (int i = 1; (key >= pFather->GetElement(i)) && (i <= pFather->GetCount()); i++)
{
// 如果删除的是父结点的键值,需要更改该键
if (pFather->GetElement(i) == key)
{
pFather->SetElement(i, pNode->GetElement(1)); // 更改为叶子结点新的第一个元素
}
}
return true;
}
// 找到一个最近的兄弟结点(根据B+树的定义,除了根结点,总是能找到的)
int flag = FLAG_LEFT;
CInternalNode* pBrother = (CInternalNode*)(pNode->GetBrother(flag));
// 兄弟结点填充度>50%
KEY_TYPE NewData = INVALID;
if (pBrother->GetCount() > ORDER_V)
{
pNode->MoveOneElement(pBrother);
// 修改父结点的键值
if (FLAG_LEFT == flag)
{
for (int i = 1; i <= pFather->GetCount() + 1; i++)
{
if (pFather->GetPointer(i) == pNode && i > 1)
{
pFather->SetElement(i - 1 , pNode->GetElement(1)); // 更改本结点对应的键
}
}
}
else
{
for (int i = 1; i <= pFather->GetCount() + 1; i++)
{
if (pFather->GetPointer(i) == pNode && i > 1)
{
pFather->SetElement(i - 1, pNode->GetElement(1)); // 更改本结点对应的键
}
if (pFather->GetPointer(i) == pBrother && i > 1)
{
pFather->SetElement(i - 1 , pBrother->GetElement(1)); // 更改兄弟结点对应的键
}
}
}
return true;
}
// 父结点中要删除的键
KEY_TYPE NewKey = NULL;
// 把本结点与兄弟结点合并,无论如何合并到数据较小的结点,这样父结点就无需修改指针
if (FLAG_LEFT == flag)
{
(void)pBrother->Combine(pNode);
NewKey = pNode->GetElement(1);
delete pNode;
}
else
{
(void)pNode->Combine(pBrother);
NewKey = pBrother->GetElement(1);
delete pBrother;
}
// 递归
return DeleteInternalNode(pFather, NewKey);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -