일지
알고리즘...71
niamdank
2021. 10. 18. 16:53
B 트리 삽입 오버플로우 처리
오버 플로우 처리 중 삽입 가능한 형제가 존재한 경우에 대한 처리를 구현한다.
오버 플로우가 발생한 노드의 형제 노드의 위치가 왼쪽인 경우 가장 작은 키를 부모에 넣고 부모의 형제 노드를 가리키는 키와 값을 바꾼 뒤 해당 키를 형제 노드에 삽입하면 된다.
이를 위해 Node의 Insert 함수를 수정하여 Key가 직접 입력된 경우를 적절하게 처리해 주는 함수를 추가한다.
BTreeNodeKey
/// <summary>
/// 새 키를 기존 키의 오른쪽에 삽입한다.
/// </summary>
/// <param name="newKey">삽입할 키</param>
void BTreeNodeKey::AddKeyToNext(BTreeNodeKey* newKey)
{
BTreeNodeKey* nextKey{ next };
if (nextKey != nullptr)
{
nextKey->prev = newKey;
newKey->next = nextKey;
}
newKey->prev = this;
next = newKey;
}
/// <summary>
/// 다른 키와 value를 교환한다.
/// </summary>
/// <param name="other">다른 키</param>
void BTreeNodeKey::SwapValue(BTreeNodeKey* other)
{
int temp{ value };
value = other->value;
other->value = temp;
}
BTreeNode
/// <summary>
/// 노드에 데이터를 삽입한다.
/// </summary>
/// <param name="data">삽입할 데이터</param>
/// <returns>성공 여부</returns>
bool BTreeNode::Insert(int data)
{
BTreeNodeKey* newKey{ keyManager->Pop() };
newKey->Set(data);
return Insert(newKey);
}
/// <summary>
/// 주어진 키를 노드의 키에 삽입한다.
/// </summary>
/// <param name="key">삽입할 키</param>
/// <returns>성공 여부</returns>
bool BTreeNode::Insert(BTreeNodeKey* newKey)
{
if (keyRoot == nullptr)
{
keyRoot = newKey;
}
else
{
// 새 값이 노드에서 가장 작은 경우
if (newKey->value < keyRoot->value)
{
keyRoot->AddKeyToPrev(newKey);
keyRoot = newKey;
}
else
{
BTreeNodeKey* key{ keyRoot };
BTreeNodeKey* prevKey{ nullptr };
while (key != nullptr)
{
if (newKey->value < key->value)
{
prevKey = nullptr;
key->AddKeyToPrev(newKey);
break;
}
prevKey = key;
key = key->next;
}
// 새 값이 노드에서 가장 큰 경우
if (prevKey != nullptr)
{
prevKey->AddKeyToNext(newKey);
}
}
}
size++;
return size <= TotalKeyCount;
}
/// <summary>
/// 가장 작은 키를 노드에서 떼어내 반환한다.
/// </summary>
/// <returns>가장 작은 키</returns>
BTreeNodeKey* BTreeNode::GetSmallestKey()
{
BTreeNodeKey* key{ nullptr };
if (keyRoot != nullptr)
{
key = keyRoot;
keyRoot = keyRoot->next;
keyRoot->prev = nullptr;
}
return key;
}
/// <summary>
/// 가장 큰 키를 노드에서 떼어내 반환한다.
/// </summary>
/// <returns>가장 큰 키</returns>
BTreeNodeKey* BTreeNode::GetBiggestKey()
{
BTreeNodeKey* key{ nullptr };
if (keyRoot != nullptr)
{
key = keyRoot;
while (key->next != nullptr)
{
key = key->next;
}
BTreeNodeKey* prev{ key->prev };
if (prev != nullptr)
{
prev->next = nullptr;
key->prev = nullptr;
}
}
return key;
}
BTree
/// <summary>
/// 오버플로우 발생한 노드를 정리한다.
/// </summary>
/// <param name="node">오버 플로우가 발생한 노드</param>
void BTree::ClearOverflow(BTreeNode* node)
{
bool isDone{ false };
BTreeNode* p{ node->parent };
// 루트 노드가 아닌 경우
if (p != nullptr)
{
BTreeNodeKey* lsKey{ nullptr };
BTreeNodeKey* rsKey{ p->keyRoot };
while (rsKey != nullptr)
{
if (rsKey->left == node)
{
break;
}
lsKey = rsKey;
rsKey = rsKey->next;
}
// 왼쪽 형제가 존재하고 삽입 가능한 경우
if (lsKey != nullptr && lsKey->left != nullptr
&& lsKey->left->IsAbleToInsert())
{
BTreeNodeKey* key{ node->GetSmallestKey() };
lsKey->SwapValue(key);
lsKey->left->Insert(key);
isDone = true;
}
// 오른쪽 형제가 존재하고 삽입 가능한 경우
else if (rsKey != nullptr && rsKey->right != nullptr
&& rsKey->right->IsAbleToInsert())
{
BTreeNodeKey* key{ node->GetBiggestKey() };
rsKey->SwapValue(key);
rsKey->right->Insert(key);
isDone = true;
}
}
// 삽입 가능한 형제가 없는 경우
if (!isDone)
{
}
}