Last active
March 29, 2024 17:06
-
-
Save gowoonsori/a725e29ef1880f0592fe5760f4908c6b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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