Skip to content

Instantly share code, notes, and snippets.

@gowoonsori
Last active March 29, 2024 17:06
Show Gist options
  • Save gowoonsori/a725e29ef1880f0592fe5760f4908c6b to your computer and use it in GitHub Desktop.
Save gowoonsori/a725e29ef1880f0592fe5760f4908c6b to your computer and use it in GitHub Desktop.
/*
* C++ μ΄μš©ν•˜μ—¬ Red Black Tree κ΅¬ν˜„ν•˜κΈ°
*
* λͺ©μ  : Red Black Tree 곡뢀 ν•˜κΈ° μœ„ν•΄ μž‘μ„±ν–ˆμœΌλ©°,
* C++ μ΄μš©ν•˜μ—¬ μž‘μ„±ν•˜μ‹œλŠ” λΆ„λ“€μ—κ²Œ 도움이 되고자 ν–ˆλ‹€.
*
* μ„€λͺ… : key 값은 int만 κ°€λŠ₯ ν•˜λ©° 쀑볡 keyλŠ” ν—ˆμš© x
* 이쀑 μ—°κ²° 리슀트둜 κ΅¬ν˜„
* Red / Black은 μ‹λ³„ν•˜κΈ° μ‰½κ²Œ enum이용 ν–ˆμœΌλ©°, bool μ΄μš©μ‹œ 데이터 크기 μ ˆμ•½
*
* class RBTree
*
* λ³€μˆ˜ : root node => rootλ…Έλ“œλŠ” 항상 black
* leaf node => 끝에 ν•΄λ‹Ήν•˜λŠ” λ…Έλ“œλ“€μ€ leaf node듀을 가지고 μžˆλ‹€.
* leaf nodeλΌλŠ” κ²ƒλ§Œ μ•Œλ©΄ 되기 λ•Œλ¬Έμ— μƒˆλ‘œμš΄ λ…Έλ“œ μ‚½μž… λ•Œλ§ˆλ‹€ leaf nodeλ₯Ό 생성 해쀄 ν•„μš”μ—†μ΄
* λͺ¨λ“  말단 λ…Έλ“œλ“€μ€ 이 leaf nodeλ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹μœΌλ‘œ κ΅¬ν˜„
* leaf nodeλŠ” 항상 black
*
* μƒμ„±μž : RBTREE => node ꡬ쑰체 생성후
* 색은 black μ΄ˆκΈ°ν™”
* λͺ¨λ“  μžμ‹μ€ nullptr둜 μ΄ˆκΈ°ν™”.
*
* ν•¨μˆ˜ : IsKey => key값이 μžˆλŠ”μ§€ κ²€μ‚¬ν•˜λŠ” ν•¨μˆ˜
* Insert => μ‚½μž… ν•¨μˆ˜
* InsertFixUp => μ‚½μž… ν›„ κ·œμΉ™ κΉ¨μ‘Œμ„ μ‹œ μž¬μ‘°μ • ν•¨μˆ˜
* Delete => μ‚­μ œ ν•¨μˆ˜
* DeleteFixUp => μ‚­μ œ ν›„ κ·œμΉ™ κΉ¨μ‘Œμ„ μ‹œ μž¬μ‘°μ • ν•¨μˆ˜
* Transplant => μ‚­μ œ μ‹œ μ΄μš©ν•˜λ©°, μ‚­μ œν•  λ…Έλ“œμ˜ μžμ‹ λ…Έλ“œλ₯Ό λΆ€λͺ¨λ…Έλ“œμ— μ—°κ²°ν•΄μ£ΌλŠ” ν•¨μˆ˜
* RotateRight(x) => xκΈ°μ€€ 였λ₯Έμͺ½μœΌλ‘œ νšŒμ „
* RotateLeft(x) => xκΈ°μ€€ μ™Όμͺ½μœΌλ‘œ νšŒμ „
*
* Inorder,Preorder,Postorder => 순회 ν•¨μˆ˜
* tree_minimum(x), tree_maximum(x) => λ…Έλ“œ x κΈ°μ€€μœΌλ‘œ κ°€μž₯ μ™Όμͺ½, 였λ₯Έμͺ½ return ν•¨μˆ˜
*
* DisplayMenu, SelectMenu => 초기 Menu판 print ν•¨μˆ˜
* Insert_helper,Delete_helper,order_helper,print_helper => 각각 μˆ˜ν–‰μ‹œ μž…λ ₯λ°›κ³  쑰건 μ—λŸ¬ 처리 μœ„ν•œ ν•¨μˆ˜ 와 tree print ν•΄μ£ΌλŠ” ν•¨μˆ˜
*
* InsertFixUpκ³Ό DeleteFixUpμ—μ„œ 각 case에 λŒ€ν•œ μ„€λͺ…은 github에 적어 λ†“μ•˜λ‹€.
*
* μž‘μ„±μž : gowoonsori
* github : https://github.com/gowoonsori/my-tech/tree/master/dataStructure/Tree
* ν•΄λ‹Ή source gist : https://gist.github.com/gowoonsori/a725e29ef1880f0592fe5760f4908c6b
*/
#include <iostream>
enum Color
{
RED,
BLACK
};
struct node
{
int key;
node *left = nullptr;
node *right = nullptr;
node *parent = nullptr;
Color color = BLACK;
};
typedef node *NodePtr;
class RBTREE
{
private:
NodePtr root; //루트 λ…Έλ“œ
NodePtr leafNode; //λ‹¨λ§λ…Έλ“œ
//key값이 μžˆλŠ”μ§€ μ—†λŠ”μ§€ 검사 있으면 pointer κ°’, μ—†μœΌλ©΄ nullptr
NodePtr IsKey(int item)
{
NodePtr t = root;
NodePtr parent = NULL;
/*key값을 μ°Ύκ±°λ‚˜ μ—†λ‹€λ©΄ break*/
while (t != NULL && t->key != item)
{
parent = t;
t = (item < parent->key) ? parent->left : parent->right;
}
return t;
}
void Insert(int item)
{
// x : μ‚½μž…ν•  κ³³ μ°ΎκΈ°μœ„ν•œ 포인터 | y : μ‚½μž…ν•  곳의 λΆ€λͺ¨λ…Έλ“œ
NodePtr x = this->root, y = nullptr;
NodePtr z = new node();
z->key = item;
z->color = RED;
z->parent = nullptr;
z->left = leafNode;
z->right = leafNode;
/*BST의 일반 μ‚½μž… μ—°μ‚°*/
while (x != leafNode)
{
y = x;
if (x->key < item)
x = x->right;
else
x = x->left;
}
z->parent = y;
if (y == nullptr)
root = z;
else if (z->key > y->key)
y->right = z;
else
y->left = z;
//zκ°€ rootλ…Έλ“œλΌλ©΄
if (z->parent == nullptr)
{
z->color = BLACK;
return;
}
// z의 λΆ€λͺ¨λ…Έλ“œκ°€ rootλ…Έλ“œλΌλ©΄ Fix Up ν•„μš”μ—†μ΄ red컬러둜 λΆ™μ—¬μ£Όλ©΄ λœλ‹€.
if (z->parent->parent == nullptr)
{
return;
}
InsertFixUp(z);
return;
}
void InsertFixUp(NodePtr z)
{
/*root λ…Έλ“œκ°€ μ•„λ‹ˆκ³  λΆ€λͺ¨ 색이 red라면*/
while (z != root && z->parent->color == RED)
{
NodePtr grandparent = z->parent->parent;
NodePtr uncle = (z->parent == grandparent->left) ? grandparent->right : grandparent->left;
bool side = (z->parent == grandparent->left) ? true : false; //if p[z]κ°€ p[p[z]]의 μ™Όμͺ½ μžμ‹μ΄λ©΄ 1 / 였λ₯Έμͺ½μ΄λ©΄ 0
/*case 1*/
if (uncle && uncle->color == RED)
{
z->parent->color = BLACK;
uncle->color = BLACK;
grandparent->color = RED;
z = grandparent;
}
/*case 2
side == true ) p[z]λŠ” p[p[z]]의 μ™Όμͺ½ μžμ‹ 인 κ²½μš°μ΄λ‹€.
side == false ) p[z]λŠ” p[p[z]]의 였λ₯Έμͺ½ μžμ‹ 인 κ²½μš°μ΄λ‹€. */
else
{
/*case 2-1*/
if (z == (side ? z->parent->right : z->parent->left))
{
z = z->parent;
side ? RotateLeft(z) : RotateRight(z);
}
/*case 2-2*/
z->parent->color = BLACK;
grandparent->color = RED;
side ? RotateRight(grandparent) : RotateLeft(grandparent);
}
}
root->color = BLACK;
}
bool Delete(int item)
{
NodePtr z = IsKey(item);
if (!z)
return false;
else
{
NodePtr x, y;
Color OriginalColor = z->color;
/*μžμ‹μ΄ μ—†κ±°λ‚˜ 1개인 경우
μ‚­μ œν•  λ…Έλ“œ(z)κ°€ λΈ”λž™μ΄λ©΄ doulbe redμ΄λ―€λ‘œ fix*/
if (z->left == leafNode)
{
x = z->right;
Transplant(z, z->right);
}
else if (z->right == leafNode)
{
x = z->left;
Transplant(z, z->left);
}
else
{
y = tree_minimum(z->right);
OriginalColor = y->color;
x = y->right; //y의 μ™Όμͺ½ μžμ‹μ€ μ—†λ‹€.
if (y->parent == z)
{ //z의 였λ₯Έμͺ½ μžμ‹μ΄ κ°€μž₯ μž‘μ€ key
x->parent = y; // xκ°€ leafnode일 λ•Œ, fixν•˜κ²Œ 될 λ•Œ μ‚¬μš©
}
else
{
Transplant(y, y->right);
y->right = z->right;
y->right->parent = y;
}
Transplant(z, y);
y->left = z->left;
y->left->parent = y;
y->color = z->color;
}
delete z;
if (OriginalColor == BLACK)
{
DelteFixUp(x);
}
}
return true;
}
void DelteFixUp(NodePtr x)
{
NodePtr s; //ν˜•μ œλ…Έλ“œ s
//rootμ΄κ±°λ‚˜ double black 이 κΉ¨μ§ˆλ•Œ κΉŒμ§€
while (x != root && x->color == BLACK)
{
/* xκ°€ p[x]의 μ™Όμͺ½μžμ‹μΈ 경우 */
if (x == x->parent->left)
{
s = x->parent->right;
// case 1
if (s->color == RED)
{
s->color = BLACK;
x->parent->color = RED;
RotateLeft(x->parent);
s = x->parent->right;
}
// case 2
if (s->left->color == BLACK && s->right->color == BLACK)
{
s->color = RED;
x = x->parent;
}
else
{
// case 3
if (s->right->color == BLACK)
{
s->left->color = BLACK;
s->color = RED;
RotateRight(s);
s = x->parent->right;
}
// case 4
s->color = x->parent->color;
x->parent->color = BLACK;
s->right->color = BLACK;
RotateLeft(x->parent);
x = root;
}
}
/*xκ°€ p[x]의 였λ₯Έμͺ½ μžμ‹μΈ 경우*/
else
{
s = x->parent->left;
// case 1
if (s->color == RED)
{
s->color = BLACK;
x->parent->color = RED;
RotateRight(x->parent);
s = x->parent->left;
}
// case 2
if (s->left->color == BLACK && s->right->color == BLACK)
{
s->color = RED;
x = x->parent;
}
else
{
// case 3
if (s->left->color == BLACK)
{
s->right->color = BLACK;
s->color = RED;
RotateLeft(s);
s = x->parent->left;
}
// case 4
s->color = x->parent->color;
x->parent->color = BLACK;
s->left->color = BLACK;
RotateRight(x->parent);
x = root;
}
}
}
x->color = BLACK;
root->color = BLACK;
}
/* u의 μœ„μΉ˜μ— vλ₯Ό 이식 */
void Transplant(NodePtr u, NodePtr v)
{
if (u->parent == nullptr)
root = v;
else if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
v->parent = u->parent;
}
/*xλ₯Ό μ€‘μ‹¬μœΌλ‘œ μ™Όμͺ½μœΌλ‘œ νšŒμ „*/
void RotateLeft(NodePtr x)
{
NodePtr y;
y = x->right;
x->right = y->left;
if (y->left != leafNode)
{
y->left->parent = x;
}
y->parent = x->parent;
if (!x->parent)
{
root = y;
}
else if (x == x->parent->left)
{
x->parent->left = y;
}
else
{
x->parent->right = y;
}
x->parent = y;
y->left = x;
}
/*xλ₯Ό μ€‘μ‹¬μœΌλ‘œ 였λ₯Έμͺ½μœΌλ‘œ νšŒμ „*/
void RotateRight(NodePtr y)
{
NodePtr x;
x = y->left;
y->left = x->right;
if (x->right != leafNode)
{
x->right->parent = y;
}
x->parent = y->parent;
if (!y->parent)
{
root = x;
}
else if (y == y->parent->left)
{
y->parent->left = x;
}
else
{
y->parent->right = x;
}
y->parent = x;
x->right = y;
}
/*show tree*/
void print_helper(NodePtr root, std::string indent, bool last)
{
// print the tree structure on the screen
if (root != leafNode)
{
std::cout << indent;
if (last)
{
std::cout << "R----";
indent += " ";
}
else
{
std::cout << "L----";
indent += "| ";
}
std::string sColor = (root->color == RED) ? "RED" : "BLACK";
std::cout << root->key << "(" << sColor << ")" << std::endl;
print_helper(root->left, indent, false);
print_helper(root->right, indent, true);
}
}
/*μ€‘μœ„μˆœνšŒ*/
void Inorder(NodePtr target)
{
if (target == leafNode)
return;
Inorder(target->left);
std::cout << target->key << " ";
Inorder(target->right);
}
/*ν›„μœ„μˆœνšŒ*/
void Postorder(NodePtr target)
{
if (target == leafNode)
return;
Postorder(target->left);
Postorder(target->right);
std::cout << target->key << " ";
}
/*μ „μœ„μˆœνšŒ*/
void Preorder(NodePtr target)
{
if (target == leafNode)
return;
std::cout << target->key << " ";
Preorder(target->left);
Preorder(target->right);
}
public:
RBTREE()
{
leafNode = new node;
leafNode->color = BLACK;
leafNode->left = nullptr;
leafNode->right = nullptr;
leafNode->parent = nullptr;
root = leafNode;
}
//μ΅œμ†Ÿκ°’ μ°ΎκΈ°
NodePtr tree_minimum(NodePtr x)
{
while (x->left != leafNode)
{
x = x->left;
}
return x;
}
//μ΅œλŒ“κ°’ μ°ΎκΈ°
NodePtr tree_maximum(NodePtr x)
{
while (x->right != leafNode)
{
x = x->right;
}
return x;
}
void DisplayMenuBoard()
{
std::cout << " Menu " << std::endl;
std::cout << " 1. Insert Key " << std::endl;
std::cout << " 2. Delete Key " << std::endl;
std::cout << " 3. Show Tree " << std::endl;
std::cout << " 4. choose order " << std::endl;
std::cout << " 5. show Menu " << std::endl;
std::cout << " 6. clear Display " << std::endl;
std::cout << " 7. exit " << std::endl;
std::cout << std::endl;
}
void SelectMenu()
{
DisplayMenuBoard();
int i = -1;
while (i != 8)
{
std::cout << "--> select : ";
std::cin >> i;
switch (i)
{
case 1:
Insert_helper();
break;
case 2:
Delete_helper();
break;
case 3:
print_helper(root, "", true);
break;
case 4:
Order_helper();
break;
case 5:
DisplayMenuBoard();
break;
case 6:
system("cls");
DisplayMenuBoard();
break;
case 7:
return;
default:
std::cout << " !!! Wrong entered !!!\n"
<< std::endl;
}
}
}
void Insert_helper()
{
int item;
std::cout << "Key to insert : ";
std::cin >> item;
if (IsKey(item))
{
std::cout << "!!! " << item << " is already exists !!!\n";
return;
}
Insert(item);
}
void Delete_helper()
{
int item;
std::cout << "Key to delete : ";
std::cin >> item;
if (!Delete(item))
{
std::cout << "!!! " << item << " is not exists !!!\n";
return;
}
return;
}
void Order_helper()
{
int i;
std::cout << " == Order Menu ==" << std::endl;
std::cout << " 1. PreOrder" << std::endl;
std::cout << " 2. InOrder" << std::endl;
std::cout << " 3. PostOrder" << std::endl;
std::cout << " 4. exit" << std::endl;
std::cout << " --> select : ";
std::cin >> i;
switch (i)
{
case 1:
Preorder(this->root);
std::cout << std::endl;
break;
case 2:
Inorder(this->root);
std::cout << std::endl;
break;
case 3:
Postorder(this->root);
std::cout << std::endl;
break;
case 4:
return;
default:
std::cout << " !!! Wrong enter !!!\n"
<< std::endl;
break;
}
return;
}
};
int main()
{
RBTREE tree;
tree.SelectMenu();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment