-
레드 블랙 트리 삽입 메서드 구현 진행
RedBlackTree.h
#pragma once #include "../Common.h" enum class NodeColor { Red, Black }; /// <summary> /// 레드 블랙 트리에 사용할 노드 /// </summary> struct RedBlackNode { RedBlackNode() : data{ 0 }, color{ NodeColor::Red }, parent{ nullptr }, left{ nullptr }, right{ nullptr } {} RedBlackNode(int data) : data{ data }, color{ NodeColor::Red }, parent{ nullptr }, left{ nullptr }, right{ nullptr } {} void Clear() { data = 0; parent = nullptr; left = nullptr; right = nullptr; } bool HasParent() { return parent != nullptr; } bool IsRightChild() { return (parent->right == this); } RedBlackNode* GetSibling() { RedBlackNode* sibling{ nullptr }; if (HasParent()) { if (parent->left == this) { sibling = parent->right; } else { sibling = parent->left; } } return sibling; } int data; NodeColor color; RedBlackNode* parent; RedBlackNode* left; RedBlackNode* right; }; /// <summary> /// 레드 블랙 트리에서 노드의 재활용을 위한 매니저 /// </summary> class RedBlackNodeManager { public: RedBlackNodeManager(RedBlackNode* nil); ~RedBlackNodeManager(); void Push(RedBlackNode* node); RedBlackNode* Pop(); private: RedBlackNode* _nil; RedBlackNode* _nodes; }; /// <summary> /// 연결 자료구조를 이용한 레드 블랙 트리 /// </summary> class RedBlackTree { public: RedBlackTree(); ~RedBlackTree(); bool Exists(int data); const RedBlackNode& Search(int data); void Insert(int data); void Delete(int data); private: RedBlackNode* Insert(RedBlackNode* parent, int data); void Delete(RedBlackNode* node); RedBlackNode& GetNode(int data); bool IsLeftNode(RedBlackNode* node); bool IsRightNode(RedBlackNode* node); private: RedBlackNode* _root; RedBlackNode* _nil; RedBlackNodeManager* _nodeManager; };
RedBlackTree.cpp
#include "RedBlackTree.h" #pragma region 노드 매니저 /// <summary> /// 레드 블랙 노드의 매니저에 nil 노드 등록 /// </summary> /// <param name="nil">nil 노드</param> RedBlackNodeManager::RedBlackNodeManager(RedBlackNode* nil) : _nil(nil), _nodes(nullptr) { } /// <summary> /// 종료 전 생성하 노드 제거 /// </summary> RedBlackNodeManager::~RedBlackNodeManager() { while (_nodes != nullptr) { RedBlackNode* temp{ _nodes }; _nodes = _nodes->left; delete temp; } } /// <summary> /// 사용 완료한 노드를 매니저에 저장 /// </summary> /// <param name="node">사용후 반환할 노드</param> void RedBlackNodeManager::Push(RedBlackNode* node) { node->left = _nodes; _nodes = node; } /// <summary> /// 노드가 필요한 경우 매니저에서 반환 /// </summary> /// <returns>사용할 수 있는 노드</returns> RedBlackNode* RedBlackNodeManager::Pop() { RedBlackNode* node{ _nodes }; if (node != nullptr) { _nodes = node->left; node->Clear(); } else { node = new RedBlackNode(); } node->color = NodeColor::Red; node->left = node->right = _nil; return node; } #pragma endregion #pragma region 레드 블랙 트리 /// <summary> /// 레드 블랙 트리에 필요한 정보 세팅 /// </summary> RedBlackTree::RedBlackTree() : _root(nullptr) { _nil = new RedBlackNode(); _nil->color = NodeColor::Black; _nodeManager = new RedBlackNodeManager(_nil); } /// <summary> /// 종료 전 남은 노드 제거 처리 /// </summary> RedBlackTree::~RedBlackTree() { while (_root != nullptr) { Delete(_root); } } /// <summary> /// 레드 블랙 트리에서 특정 값을 가지는 노드가 존재하는지 여부 확인 /// </summary> /// <param name="data">찾을 값</param> /// <returns>존재 여부</returns> bool RedBlackTree::Exists(int data) { RedBlackNode* node{ _root }; while (node != nullptr) { if (node->data == data) { return true; } else if (node->data > data) { node = node->left; } else { node = node->right; } } return false; } /// <summary> /// 레드 블랙 트리에서 주어진 값을 가진 노드를 반환 /// </summary> /// <param name="data">찾을 값</param> /// <returns>값을 가진 노드, 없으면 nullptr</returns> const RedBlackNode& RedBlackTree::Search(int data) { return GetNode(data); } /// <summary> /// 레드 블랙 트리에 값을 가지는 노드를 삽입 /// </summary> /// <param name="data">삽입할 값</param> void RedBlackTree::Insert(int data) { if (Exists(data)) { return; } RedBlackNode* x{ Insert(_root, data) }; RedBlackNode* p{ x->parent }; if (x == _root || p->color == NodeColor::Black) { return; } RedBlackNode* y{ x->GetSibling() }; RedBlackNode* p2{ p->parent }; RedBlackNode* s{ p->GetSibling() }; // case 1 if (s->color == NodeColor::Red) { } else { // case 2-1 if (x->IsRightChild()) { } // case 2-2 else { } } } /// <summary> /// 레드 블랙 트리에서 해당 값을 가지는 노드를 제거 /// </summary> /// <param name="data">제거할 값</param> void RedBlackTree::Delete(int data) { if (!Exists(data)) { return; } RedBlackNode* node{ &GetNode(data) }; Delete(node); } /// <summary> /// 레드 블랙 트리 삽입 처리 /// </summary> /// <param name="parent">삽입해야 할 노드의 부모</param> /// <param name="data">삽입할 값</param> /// <returns>새로 삽입한 노드</returns> RedBlackNode* RedBlackTree::Insert(RedBlackNode* parent, int data) { if (parent == nullptr) { RedBlackNode* node{ _nodeManager->Pop() }; node->data = data; _root = node; return node; } else if (parent->data > data) { if (parent->left == nullptr) { RedBlackNode* node{ _nodeManager->Pop() }; node->data = data; node->parent = parent; parent->left = node; return node; } else { return Insert(parent->left, data); } } else { if (parent->right == nullptr) { RedBlackNode* node{ _nodeManager->Pop() }; node->data = data; node->parent = parent; parent->right = node; return node; } else { return Insert(parent->right, data); } } } /// <summary> /// 레드 블랙 트리 제거 처리 /// </summary> /// <param name="node">제거할 노드</param> void RedBlackTree::Delete(RedBlackNode* node) { RedBlackNode* parent{ node->parent }; if (node->left == nullptr && node->right == nullptr) { if (IsLeftNode(node)) { parent->left = nullptr; } else if (IsRightNode(node)) { parent->right = nullptr; } else { _root = nullptr; } _nodeManager->Push(node); } else if (node->left != nullptr && node->right == nullptr || node->left == nullptr && node->right != nullptr) { RedBlackNode* child{ node->left }; if (child == nullptr) { child = node->right; } if (IsLeftNode(node)) { parent->left = child; } else if (IsRightNode(node)) { parent->right = child; } else { _root = child; } child->parent = parent; _nodeManager->Push(node); } else { RedBlackNode* child{ node->left }; while (child->right != nullptr) { child = child->right; } node->data = child->data; Delete(child); } } RedBlackNode& RedBlackTree::GetNode(int data) { RedBlackNode* node{ _root }; while (node != nullptr) { if (node->data == data) { break; } else if (node->data > data) { node = node->left; } else { node = node->right; } } return *node; } /// <summary> /// 해당 노드가 부모 노드의 왼쪽 자식인지 여부 /// </summary> /// <param name="node">확인할 노드</param> /// <returns>왼쪽 자식인지 여부</returns> bool RedBlackTree::IsLeftNode(RedBlackNode* node) { return node->parent != nullptr && node->parent->left == node; } /// <summary> /// 해당 노드가 부모 노드의 오른쪽 자식인지 여부 /// </summary> /// <param name="node">확인할 노드</param> /// <returns>오른쪽 자식인지 여부</returns> bool RedBlackTree::IsRightNode(RedBlackNode* node) { return node->parent != nullptr && node->parent->right == node; } #pragma endregion
회전할 때 노드 자체를 회전하는 건지 아니면 색만 교환하는 건지 확인이 필요하다.