Set은 레드블랙트리를 활용해서 데이터가 삽입, 삭제될 때마다 자동으로 트리의 균형을 맞추며 정렬하는 자료구조이다.
레드블랙트리 알고리즘에 따른 Insert까지는 일단 구현을 해보았다.
#pragma once
#include "Node.h"
#include <queue>
#include <string>
template<typename DataType>
class Set
{
private:
using MyNode = typename TreeNode<DataType>;
public:
using Iterator = typename BidirectionalIterator<DataType>;
public:
Set()
{
NilNode = new MyNode();
NilNode->Color = MyNode::NodeColor::Black;
NilNode->LeftChild = NilNode;
NilNode->RightChild = NilNode;
}
void Insert(const DataType& _Data)
{
MyNode* NewNode = InsertNewElement(_Data);
if (NewNode == nullptr)
{
return;
}
MySize++;
//더블레드발생
while(NewNode != nullptr && NewNode != RootNode && (NewNode->Color == MyNode::NodeColor::Red && NewNode->Parent->Color == MyNode::NodeColor::Red))
{
NewNode = Balancing(NewNode);
}
}
private:
MyNode* InsertNewElement(const DataType& _Data)
{
MyNode* NewNode = nullptr;
if (RootNode == nullptr)
{
NewNode = CreateNewNode(_Data);
RootNode = NewNode;
RootNode->Parent = NilNode;
RootNode->Color = MyNode::NodeColor::Black;
}
else
{
MyNode* CurNode = RootNode;
while (true)
{
if (_Data < CurNode->Data)
{
if (CurNode->LeftChild == NilNode)
{
NewNode = CreateNewNode(_Data);
CurNode->LeftChild = NewNode;
NewNode->Parent = CurNode;
break;
}
else
{
CurNode = CurNode->LeftChild;
}
}
else if (_Data > CurNode->Data)
{
if (CurNode->RightChild == NilNode)
{
NewNode = CreateNewNode(_Data);
CurNode->RightChild = NewNode;
NewNode->Parent = CurNode;
break;
}
else
{
CurNode = CurNode->RightChild;
}
}
if (_Data == CurNode->Data)
{
return NewNode;
}
}
}
return NewNode;
}
MyNode* CreateNewNode(const DataType& _Data)
{
MyNode* NewNode = new MyNode();
NewNode->Data = _Data;
NewNode->Color = MyNode::NodeColor::Red;
NewNode->LeftChild = NilNode;
NewNode->RightChild = NilNode;
return NewNode;
}
MyNode* Balancing(MyNode* _InsertedNode)
{
if (_InsertedNode->Parent == NilNode)
{
return _InsertedNode;
}
MyNode* UncleNode = nullptr;
MyNode* ParentNode = _InsertedNode->Parent;
MyNode* Ancestor = _InsertedNode->Parent->Parent;
if (ParentNode == Ancestor->LeftChild)
{
UncleNode = Ancestor->RightChild;
}
else if (ParentNode == Ancestor->RightChild)
{
UncleNode = Ancestor->LeftChild;
}
MyNode* ReturnNode = nullptr;
if (UncleNode->Color == MyNode::NodeColor::Black)
{
ReturnNode = Restructuring(_InsertedNode, UncleNode);
}
else if (UncleNode->Color == MyNode::NodeColor::Red)
{
ReturnNode = ReColoring(_InsertedNode, UncleNode);
}
return ReturnNode;
}
MyNode* ReColoring(MyNode* _InsertedNode, MyNode* _UncleNode)
{
_InsertedNode->Parent->Color = MyNode::NodeColor::Black;
_UncleNode->Color = MyNode::NodeColor::Black;
_InsertedNode->Parent->Parent->Color = MyNode::NodeColor::Red;
RootNode->Color = MyNode::NodeColor::Black;
return _InsertedNode->Parent->Parent;
}
MyNode* Restructuring(MyNode* _InsertedNode, MyNode* _UncleNode)
{
MyNode* ParentNode = _InsertedNode->Parent;
MyNode* AncestorNode = _InsertedNode->Parent->Parent;
if (ParentNode == AncestorNode->LeftChild && _InsertedNode == ParentNode->LeftChild)
{
if (ParentNode->RightChild != NilNode)
{
AncestorNode->LeftChild = ParentNode->RightChild;
AncestorNode->LeftChild->Parent = AncestorNode;
}
ParentNode->RightChild = AncestorNode;
ParentNode->Parent = AncestorNode->Parent;
if (AncestorNode == RootNode)
{
RootNode = ParentNode;
}
else if (AncestorNode->Parent->LeftChild == AncestorNode)
{
AncestorNode->Parent->LeftChild = ParentNode;
}
else if (AncestorNode->Parent->RightChild == AncestorNode)
{
AncestorNode->Parent->RightChild = ParentNode;
}
AncestorNode->Parent = ParentNode;
AncestorNode->LeftChild = NilNode;
ParentNode->Color = MyNode::NodeColor::Black;
ParentNode->LeftChild->Color = MyNode::NodeColor::Red;
ParentNode->RightChild->Color = MyNode::NodeColor::Red;
}
else if (ParentNode == AncestorNode->LeftChild && _InsertedNode == ParentNode->RightChild)
{
_InsertedNode->LeftChild = ParentNode;
_InsertedNode->RightChild = AncestorNode;
ParentNode->RightChild = NilNode;
AncestorNode->LeftChild = NilNode;
_InsertedNode->Parent = AncestorNode->Parent;
if (AncestorNode == RootNode)
{
RootNode = _InsertedNode;
}
else if (AncestorNode->Parent->LeftChild == AncestorNode)
{
AncestorNode->Parent->LeftChild = _InsertedNode;
}
else if (AncestorNode->Parent->RightChild == AncestorNode)
{
AncestorNode->Parent->RightChild = _InsertedNode;
}
ParentNode->Parent = _InsertedNode;
AncestorNode->Parent = _InsertedNode;
_InsertedNode->Color = MyNode::NodeColor::Black;
_InsertedNode->LeftChild->Color = MyNode::NodeColor::Red;
_InsertedNode->RightChild->Color = MyNode::NodeColor::Red;
}
else if (ParentNode == AncestorNode->RightChild && _InsertedNode == ParentNode->LeftChild)
{
_InsertedNode->LeftChild = AncestorNode;
_InsertedNode->RightChild = ParentNode;
ParentNode->LeftChild = NilNode;
AncestorNode->RightChild = NilNode;
_InsertedNode->Parent = AncestorNode->Parent;
if (AncestorNode == RootNode)
{
RootNode = _InsertedNode;
}
else if (AncestorNode->Parent->LeftChild == AncestorNode)
{
AncestorNode->Parent->LeftChild = _InsertedNode;
}
else if (AncestorNode->Parent->RightChild == AncestorNode)
{
AncestorNode->Parent->RightChild = _InsertedNode;
}
ParentNode->Parent = _InsertedNode;
AncestorNode->Parent = _InsertedNode;
_InsertedNode->Color = MyNode::NodeColor::Black;
_InsertedNode->LeftChild->Color = MyNode::NodeColor::Red;
_InsertedNode->RightChild->Color = MyNode::NodeColor::Red;
}
else if (ParentNode == AncestorNode->RightChild && _InsertedNode == ParentNode->RightChild)
{
if (ParentNode->LeftChild != NilNode)
{
AncestorNode->RightChild = ParentNode->LeftChild;
ParentNode->LeftChild->Parent = AncestorNode;
}
ParentNode->LeftChild = AncestorNode;
ParentNode->Parent = AncestorNode->Parent;
if (AncestorNode == RootNode)
{
RootNode = ParentNode;
}
else if (AncestorNode->Parent->LeftChild == AncestorNode)
{
AncestorNode->Parent->LeftChild = ParentNode;
}
else if (AncestorNode->Parent->RightChild == AncestorNode)
{
AncestorNode->Parent->RightChild = ParentNode;
}
AncestorNode->Parent = ParentNode;
AncestorNode->RightChild = NilNode;
ParentNode->Color = MyNode::NodeColor::Black;
ParentNode->LeftChild->Color = MyNode::NodeColor::Red;
ParentNode->RightChild->Color = MyNode::NodeColor::Red;
}
return nullptr;
}
public:
MyNode* NilNode = nullptr;
MyNode* RootNode = nullptr;
MyNode* EndNode = nullptr;
size_t MySize = 0;
};
먼저, 처음 자료구조가 생성되면 NilNode를 만들어서 포인터를 저장해주었다.
그리고, 데이터가 삽입되면 양쪽 자식을 NilNode를 가리키게 하였고 루트노드라면 추가적으로 부모 노드또한 NilNode를 가리키도록 하였다.
데이터가 삽입되면, 먼저 크기에 따라 위치를 잡도록 하였다. 루트노드부터 시작해서 기준 노드보다 값이 작다면 왼쪽으로 값이 크다면 오른쪽으로 이동하도록 하였다.
이동이 완료되면 해당 노드와 해당 노드의 부모 노드의 색을 보고 정렬을 실시하도록 하였다. 만약, 해당 노드의 색이 Red이고 부모 노드의 색도 Red라면 레드블랙트리 알고리즘에선 균형을 잡는 과정을 거쳐야 하기 때문에 균형을 잡는 Balancing 함수를 실시하도록 하였다.
Balancing 함수 내부에선 삽입된 노드의 삼촌 노드를 확인하고, 삼촌 노드의 색에 따라 ReColoring혹은 ReStructuring 함수를 실시하도록 하였다.
Recoloring은 노드의 위치를 바꾸지 않고 색만 바꾸는 작업이고, ReStructuring는 노드의 위치를 바꾸는 작업이다.
두 함수를 통해 DoubleRed(빨간색 노드가 연속으로 이어진 상황)이 해결되고 나면 Insert 함수를 종료하도록 하였다.
'프로젝트 > STL 자료구조 구현' 카테고리의 다른 글
STL 자료구조 구현 (9) - 노드 구조 수정 (0) | 2024.09.15 |
---|---|
STL 자료구조 구현 (8) - 양방향 이터레이터 추가 및 List 구조 수정 (0) | 2024.09.13 |
STL 자료구조 구현 (7) - 예외 처리 구조 변경, List 일부 구현 (0) | 2024.09.10 |
STL 자료구조 구현 (6) - 이터레이터 구조 변경 (0) | 2024.09.09 |
STL 자료구조 구현 (5) - VectorBase 상속 및 멤버 함수 추가 (0) | 2024.09.05 |