RB-Tree
๋ฅผ ์์ฉํ ํธ๋ฆฌ๋ก RB-Tree์ ๋ง์ ์กฐ๊ฑด์ ์ผ๋ถ ์ ๊ฑฐํ์ฌ ๊ตฌํ์ ๋ ๊ฐ๋จํ๊ฒ ๋ง๋ ํธ๋ฆฌ๋ก ๊ท ํ์ ๋ง์ถ๊ธฐ ์ํด ๋ ๋ฒจ์ ๊ฐ๋
์ ์ฌ์ฉํ ํธ๋ฆฌ์ด๋ค.
๋ถ๋ชจ์ ๋ ๋ฒจ์ด ๊ฐ์ ์์ ๋
ธ๋์ ์ฐ๊ฒฐ์ ์ํ ๋งํฌ
๋ผ๊ณ ํ๋ฉฐ, ์ด ๋
ธ๋๋ฅผ ๊ตฌ๋ถํ๊ธฐ ์ํด RED๋ผ๋ ๊ฐ๋
์ ์ด์ฉํ๋ค.
1. ํน์ง
์ผ์ชฝ ์์์ RED๊ฐ ๋ ์ ์๋ค.
์ฐ์์ผ๋ก RED๊ฐ ์ฌ ์ ์๋ค. (์ด์ค RED ๋ถ๊ฐ == ์ด์ค ์ํ ๋งํฌ)
๋ฃจํธ์์ null๊ฐ์ง leafnode๊น์ง์ ๊ฒฝ๋ก์๋ ๋์ผํ ์์ ๋ธ๋ ๋
ธ๋๊ฐ ์กด์ฌํ๋ค. (RB Tree์ ๊ท์น)
๋ชจ๋ leaf node์ ๋ ๋ฒจ์ 1์ด๋ค
๋ชจ๋ ์ผ์ชฝ ์์์ ๋ ๋ฒจ์ ๋ถ๋ชจ์ ๋ ๋ฒจ๋ณด๋ค 1 ๋ฎ๋ค
๋ชจ๋ ์ค๋ฅธ์ชฝ ์์์ ๋ ๋ฒจ์ ๋ถ๋ชจ์ ๊ฐ๊ฑฐ๋ 1 ๋ฎ๋ค
๋ชจ๋ ์ค๋ฅธ์ชฝ ์์์ ๋ ๋ฒจ์ ํ ์๋ฒ์ง ๋
ธ๋๋ณด๋ค ๋ฎ๋ค
1๋ณด๋ค ํฐ ๋ ๋ฒจ์ ๋ชจ๋ ๋
ธ๋๋ค์ 2๊ฐ์ ์์์ ๊ฐ๋๋ค
{
}
์ผ์ชฝ ํธ๋ฆฌ๋ฅผ ์ผํ ๋ณด๋ฉด RB-Tree๊ฐ์ง๋ง ์ผ์ชฝ ์์์ RED๋ฅผ ๊ฐ์ง ์๋ AA-Tree์ด๊ณ , ์ด๋ฅผ ๋ ๋ฒจ์ ๊ธฐ์ค์ผ๋ก ๋ณด๋ฉด ์ค๋ฅธ์ชฝ๊ณผ ๊ฐ์ด ๊ทธ๋ ค ๋ณผ ์ ์๋ค.
2. ์ฌ์ฉ ๊ธฐ๋ฒ
๐ Split
์ด์ค ์ํ ๋งํฌ(์ด์ค red)์ผ ์ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ง๊ธ๊น์ง ๋ค๋ฅธ BBST์ ๋์ผํ๊ฒ rotate์ ๊ฐ๋
์ด๋ค.
{
}
์ด์ค red๊ฐ ์๊ธฐ๋ ๊ฒฝ์ฐ๋ ์ ์ฌ์ง๊ณผ ๊ฐ์ด ๋ฌด์กฐ๊ฑด ์ค๋ฅธ์ชฝ ๋ฐฉํฅ์ผ๋ก ์๊ธฐ๊ธฐ ๋๋ฌธ์ ํ ์๋ฒ์ง ๋
ธ๋(35) ๊ธฐ์ค์ผ๋ก left๋ฐฉํฅ์ผ๋ก๋ง rotate์ํค๊ณ ์์ ๋ฐ๊ฟ ์ฃผ๋ฉด ๋๋ค.
ํน์ง์ผ๋ก Split์ ์ํํ๋ฉด level์ด ๋ฌ๋ผ์ง๋ค.
๐ Skew
red๊ฐ ์ผ์ชฝ์์์ผ๋ก ์์น ํ ๊ฒฝ์ฐ ๊ท์น์ ์๋ฐฐ๋๊ธฐ ๋๋ฌธ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ฌธ์ ๊ฐ ๋๋ ๋
ธ๋(40)๊ณผ ๋ถ๋ชจ ๋
ธ๋(50)์ right rotate ์ํค๊ณ ์์ ๋ฐ๊ฟ ์ด์ค ๋ ๋๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์ด๋ค.
{
}
Skew๋ ํ์ ์ ์ํํด๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์ผํ level์ ์์์ ๋ฐ๋๋ค.
3. ๊ตฌํ
์์์ ๋งํ ๊ฒ์ฒ๋ผ ์ค์ ๊ตฌํ์ ์์ด, ์ค์ red / black์ ๊ฐ์ ๊ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ์ง ์์๋ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค. ๋์ level์ ์ ์ฅํ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค.
๐ ์ฝ์
BST๊ท์น์ ๋ง๊ฒ ์ฝ์
ํ ๋ฌธ์ ๊ฐ ๋๋ ๋
ธ๋๋ฅผ Split๊ณผ Skew๋ฅผ ํตํด rebalancingํ๋ฉฐ root๊น์ง ์ฌ๋ผ๊ฐ๋ฉด์ ๊ท์น์ ์๋ฐฐ๋์ง ์์ ๋ ๊น์ง split๊ณผ skew๋ฅผ ์ํํ๋ฉด ๋๋ค.
๐ ์ญ์
1. ์ญ์ ํ ๋
ธ๋๊ฐ red leafnode
๊ทธ๋ฅ ์ ๊ฑฐํ๋ฉด ๋๋ค.
2. ์ญ์ ํ ๋
ธ๋๊ฐ ํ๋์ leaf node ์์์ ๊ฐ๋ ๋ด๋ถ ๋
ธ๋ ์ธ ๊ฒฝ์ฐ
์ญ์ ํ ๋
ธ๋๋ ๊ฒ์์์ด๊ณ , ์์์ ๋ ๋์ผ ์ ๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ์์๊ณผ ๊ฐ์ ๊ตํ ํ, ์ญ์ ํ๋ฉด ๋๋ค.
3. ๋๊ฐ์ ์์์ด ์๊ณ successor๊ฐ red์ผ ๊ฒฝ์ฐ
์ด๋ red๊ฐ leafnode์ผ ๊ฒฝ์ฐ๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๊ตํ ํ leafnode๋ฅผ ์ญ์ ํ๋ฉด ๋๋ค.
4. ๋๊ฐ์ ์์์ด ์๊ณ successor๊ฐ ํ ๊ฐ์ leaf node ์์์ ๊ฐ๋ ๊ฒฝ์ฐ
๊ฐ์ ๊ตํ ํ 2๋ฒ ๊ท์น ์ ์ฉํ๋ฉด ๋๋ค.
5. ๋๊ฐ์ ์์์ด ์๊ณ , Successor๊ฐ black leaf node ์ด๊ฑฐ๋ ์ญ์ ํ ๋
ธ๋๊ฐ black leaf node ์ผ ๊ฒฝ์ฐ
black leaf node๋ฅผ ์ญ์ ์ ๋ ๋ฒจ 2์ด์์ ๋
ธ๋๋ 2๊ฐ์ ์์์ ๊ฐ๋ ๋ค๋ ๊ท์น์ด ๊นจ์ง๋ฏ๋ก ์๋์ ๊ฐ์ ๊ณผ์ ์ ์ํํด์ฃผ์ด์ผ ํ๋ค.
{
}
Leaf node๋ฅผ ์ญ์ ํ๊ณ ๊ทธ ๋ถ๋ชจ ๋
ธ๋(15)์ ๋ ๋ฒจ์ ํ ๋จ๊ณ ๊ฐ์์ํจ๋ค.
{
}
ํ ์๋ฒ์ง ๋
ธ๋(30)์ ๋ ๋ฒจ๊ณผ ๋ถ๋ชจ ๋
ธ๋์ ๋ ๋ฒจ์ด 2์ด์ ์ฐจ์ด ๋๋ค๋ฉด ํ ์๋ฒ์ง ๋ ๋ฒจ๋ 1๊ฐ์์ํจ๋ค. {
}
๋, ํ ์๋ฒ์ง ๋
ธ๋์ ์ค๋ฅธ์ชฝ ์์(80)์ด red์ผ ๊ฒฝ์ฐ ์ค๋ฅธ์ชฝ ์์๋ ๋ ๋ฒจ 1๊ฐ์ ์ํจ๋ค. {
}
๊ทธ ํ, ํ ์๋ฒ์ง ๋
ธ๋(30)๋ฅผ ๊ธฐ์ค์ผ๋ก skew, ํ ์๋ฒ์ง ์ค๋ฅธ์ชฝ ์์(80)์ ๋
ธ๋ ๊ธฐ์ค์ผ๋ก skew ํ๋ค. {
}
ํ ์๋ฒ์ง(30) ์ค๋ฅธ์ชฝ ์์ ๋
ธ๋(80)๋ฅผ ๊ธฐ์ค์ผ๋ก skew๋ฅผ ์ํํ๋ค.
{
}
๊ทธ ํ, ํ ์๋ฒ์ง ๋
ธ๋(30)์ ๊ธฐ์ค์ผ๋ก split์ ์ํํ๋ค.
{
}
๋ง์ง๋ง์ผ๋ก ํ ์๋ฒ์ง ๋
ธ๋์ ์ค๋ฅธ์ชฝ ์์(60)์ ๊ธฐ์ค์ผ๋ก split์ ์ํํ๋ค.
๐ ์ํ ๊ณผ์
์ผ๋ฐ BST์ ๋์ผํ๊ฒ ์ ์ / ์ค์ /ํ์ ๋ก ์ํ๋ฅผ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
๐ ํ์ ๊ณผ์
AA Tree๋ํ, BBST์ด๋ฏ๋ก ํ์ ๋ฐฉ๋ฒ์ ๋์ผํ๊ณ O(lgn)์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๋ณด์ฅํ๋ค.
4. ์๊ฐ ๋ณต์ก๋
์ฝ์
๊ณผ ์ญ์ ๊ณผ์ ์์ rotate๊ฐ ์ผ์ด๋๋๋ฐ ์ด๋ O(1)๋งํผ์ ์๊ฐ์ด ์์๋๊ณ ์ด rotate๊ฐ ์ต๋ O(lgn) ๋งํผ ์ผ์ด๋๊ธฐ ๋๋ฌธ์ O(lgn)์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ๋๋ค.
5. RB Tree์ ๋น๊ต
RB-Tree์ ๋น๊ตํด์ ์์์ ์ผ์ชฝ์ ์๋ ์ค๋ฅธ์ชฝ์ ์๋ ๋์นญ์ด์ง๋ ์๊ณ ๋ฌด์กฐ๊ฑด ํ์ชฝ๋ฐฉํฅ์ผ๋ก๋ง ํ์ ๋ ํ ์ ์๊ณ case ์๋ ํจ์ฌ ์ ์ด ๊ตฌํ์ด ๊ฐ๋จํ๋ฉฐ, red/black์ ์ค๋ช
์ ์ฝ๊ฒ ํ๊ธฐ ์ํด ๊ตฌ๋ถ ์ง์ด ์ค๋ช
ํ ๊ฒ์ด์ง ์ค์ ๊ตฌํ์ ์์ด์๋ red/black์ ๊ฐ์ ๊ฐ๋ ์ถ๊ฐ ๋ฐ์ดํฐ๊ฐ ํ์ํ์ง ์๋ค. (์์์ด์ง๋ง ๊ฐ์ ๋ ๋ฒจ์ ์๋ ์์์ red๋ผ๊ณ ๋ช
๋ช
ํ์ ๋ฟ)
๊ตฌํ ์ฝ๋
github์ผ๋ก ๋ณด๊ธฐ
๐ ๊ตฌํ ์ฝ๋ (c++) ( ์ ๊ธฐ / ํผ์น๊ธฐ )
/*
* C++ ์ด์ฉํ์ฌ AA Tree ๊ตฌํํ๊ธฐ
*
* ๋ชฉ์ : AA Tree ๊ณต๋ถ ํ๊ธฐ ์ํด ์์ฑํ์ผ๋ฉฐ,
* C++ ์ด์ฉํ์ฌ ์์ฑํ์๋ ๋ถ๋ค์๊ฒ ๋์์ด ๋๊ณ ์ ํ๋ค.
*
* ์ค๋ช
: key ๊ฐ์ int๋ง ๊ฐ๋ฅ ํ๋ฉฐ ์ค๋ณต key๋ ํ์ฉ x
* ๋จ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ก ๊ตฌํ
*
* class AA Tree
*
* ๋ณ์ : root => root node
*
* ์์ฑ์ : AATREE => root ๋ฅผ null๋ก ์ด๊ธฐํ
*
* ํจ์ : IsKey => key๊ฐ์ด ์๋์ง ๊ฒ์ฌํ๋ ํจ์
*
* Insert => ์ฌ๊ท๋ฅผ ์ด์ฉํ ์ฝ์
ํจ์ (return void)
* Delete => ์ฌ๊ท๋ฅผ ์ด์ฉํ ์ญ์ ํจ์ (return void)
*
* split(x) => x๊ฐ ์ด์ค ๋ ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด rotate (return void)
* skewy(x) => x์ ์ผ์ชฝ์์์ด ๋ ๋์ผ๋ level๋ณํ ์์ด ๊ตํ (return void)
*
* 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
* ํด์ฃผ๋ ํจ์
*
* Balancing์์ ๊ฐ case์ ๋ํ ์ค๋ช
์ github์ ์ ์ด ๋์๋ค.
*
* ์์ฑ์ : gowoonsori
* github : https://github.com/gowoonsori/my-tech/tree/master/dataStructure/Tree
*/
#include <algorithm> // max() ํจ์ ์ด์ฉ
#include <iostream>
struct node {
int key;
node *left = nullptr;
node *right = nullptr;
int level = 1;
};
typedef node *NodePtr;
class AATree {
private:
NodePtr root; //๋ฃจํธ ๋
ธ๋
// key๊ฐ์ด ์๋์ง ์๋์ง ๊ฒ์ฌ ์์ผ๋ฉด pointer ๊ฐ, ์์ผ๋ฉด nullptr
NodePtr IsKey(int item) {
NodePtr t = root;
/*key๊ฐ์ ์ฐพ๊ฑฐ๋ ์๋ค๋ฉด break*/
while (t != nullptr && t->key != item) {
t = (item < t->key) ? t->left : t->right;
}
return t;
}
/*์๋ก์ด key ์ฝ์
ํจ์๋ก root๋
ธ๋ ๋ฐํ*/
void Insert(int item, NodePtr &x) {
/*์๋ก์ด ๋
ธ๋ ์ฝ์
*/
if (!x) {
NodePtr y = new node;
y->key = item;
x = y;
return;
} else if (x->key < item) {
Insert(item, x->right);
} else {
Insert(item, x->left);
}
/*์ฌ๊ท์ ์ผ๋ก Insert๋ฅผ ์ํํ๊ธฐ ๋๋ฌธ์ ์ฝ์
์์น๋ถํฐ ๋ฃจํธ๊น์ง ์ฌ๋ผ๊ฐ๋ฉฐ
๊ท์น์ด ์๋ฐฐ๋๋ ์ง ๊ฒ์ฌํ์ฌ skew, split ์ํ์ด ๊ฐ๋ฅํ๋ค.*/
skew(x);
split(x);
}
/*key ์ญ์ ํจ์*/
void Delete(int item, NodePtr &x) {
static NodePtr y, p; // y : ์ญ์ ํ ๋
ธ๋๊ฐ red leaf์ธ์ง ํ๋ณํ๊ธฐ ์ํ ํฌ์ธํฐ
// p : ์์์ด ๋๊ฐ์ธ ๊ฒฝ์ฐ successor์ ๊ฐ์ ๊ตํํ ์ญ์ ํ๊ธฐ ์ํ ํฌ์ธํฐ
if (!x) return;
y = x;
if (item < x->key) {
Delete(item, x->left);
} else {
p = x;
Delete(item, x->right);
}
/*์ญ์ ํ ๋
ธ๋๊ฐ red leaf์ด๊ฑฐ๋ successor๊ฐ red leaf์ผ๋*/
if (x == y) {
p->key = x->key;
x = x->right;
delete y;
} else {
/*x์ ๋ ๋ฒจ๊ณผ ์์์ ๋ ๋ฒจ์ด 2์ด์ ์ฐจ์ด๋ ๊ฒฝ์ฐ*/
if ((x->left && x->left->level < x->level - 1) || (x->right && x->right->level < x->level - 1)) {
/*x์ ๋ ๋ฒจ์ ๊ฐ์ ์ํค๊ณ x์ ์ค๋ฅธ์ชฝ ์์์ด ๋ ๋ ์ผ๊ฒฝ์ฐ ์์๋ ๋ ๋ฒจ ๊ฐ์*/
if (x->right->level > --x->level) {
x->right->level = x->level;
}
skew(x);
skew(x->right);
skew(x->right);
split(x);
split(x);
}
}
}
void split(NodePtr &x) {
/*x์ ์์์ x์ ๋ ๋ฒจ์ด ๊ฐ์๋ == ์ด์ค ๋ ๋*/
if (x->right && x->right->right && x->right->right->level == x->level) {
NodePtr y = x->right;
x->right = y->left;
y->left = x;
x = y;
x->level++;
}
}
void skew(NodePtr &x) {
/*x์ ์ผ์ชฝ์์์ด ๋ ๋์ผ๋ ๋ ๋ฒจ์ ๋ณํ ์์ด ๊ฐ ๊ตํ*/
if (x->left && x->left->level == x->level) {
NodePtr y = x->left;
x->left = y->right;
y->right = x;
x = y;
}
}
/*y๋ฅผ ์ค์ฌ์ผ๋ก ์ค๋ฅธ์ชฝ์ผ๋ก ํ์ */
/*show tree*/
void print_helper(NodePtr root, std::string indent, bool last) {
// print the tree structure on the screen
if (root != nullptr) {
std::cout << indent;
if (last) {
std::cout << "R----";
indent += " ";
} else {
std::cout << "L----";
indent += "| ";
}
std::cout << root->key << " (" << root->level << ")" << std::endl;
print_helper(root->left, indent, false);
print_helper(root->right, indent, true);
}
}
/*์ค์์ํ*/
void Inorder(NodePtr target) {
if (target == nullptr) return;
Inorder(target->left);
std::cout << target->key << " ";
Inorder(target->right);
}
/*ํ์์ํ*/
void Postorder(NodePtr target) {
if (target == nullptr) return;
Postorder(target->left);
Postorder(target->right);
std::cout << target->key << " ";
}
/*์ ์์ํ*/
void Preorder(NodePtr target) {
if (target == nullptr) return;
std::cout << target->key << " ";
Preorder(target->left);
Preorder(target->right);
}
public:
AATree() { this->root = nullptr; }
//์ต์๊ฐ ์ฐพ๊ธฐ
NodePtr tree_minimum(NodePtr x) {
while (x->left != nullptr) {
x = x->left;
}
return x;
}
//์ต๋๊ฐ ์ฐพ๊ธฐ
NodePtr tree_maximum(NodePtr x) {
while (x->right != nullptr) {
x = x->right;
}
return x;
}
void DisplayMenuBoard() {
std::cout << " ** AA Tree ** " << std::endl;
std::cout << " " << std::endl;
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 << "(show Menu : 5) --> 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, root);
return;
}
void Delete_helper() {
int item;
std::cout << "Key to delete : ";
std::cin >> item;
if (!IsKey(item)) {
std::cout << "!!! " << item << " is not exists !!!\n";
return;
}
Delete(item, root);
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() {
AATree tree;
tree.SelectMenu();
return 0;
}