-
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) { } }