Created
August 22, 2018 17:26
-
-
Save SubCoder1/70c2cedc44353ffc539c7567b1051028 to your computer and use it in GitHub Desktop.
Red Black Tree implementation in C++
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
#include <bits/stdc++.h> | |
using namespace std; | |
struct node { | |
int data{}; | |
node* left = nullptr; | |
node* right = nullptr; | |
node* parent = nullptr; | |
string color; | |
}; | |
class RB_TREE { | |
node* root; | |
public: | |
RB_TREE() : root(nullptr) {} | |
node* GetRoot(){ return root; } | |
void InsertNode(int stuff) { | |
if(root == nullptr){ | |
root = new node(); | |
root->data = stuff; | |
root->parent = nullptr; | |
root->color = "BLACK"; | |
cout << "Element inserted.\n"; | |
} | |
else { | |
auto linker = GetRoot(); | |
node* newnode = new node(); | |
newnode->data = stuff; | |
while(linker != nullptr){ | |
if(linker->data > stuff){ | |
if(linker->left == nullptr){ | |
linker->left = newnode; | |
newnode->color = "RED"; | |
newnode->parent = linker; | |
cout << "Element inserted.\n"; break; } | |
else { linker = linker->left; } | |
} else { | |
if(linker->right == nullptr){ | |
linker->right = newnode; | |
newnode->color = "RED"; | |
newnode->parent = linker; | |
cout << "Element inserted.\n"; break; } | |
else { linker = linker->right; } | |
} | |
} | |
RB_Insert_Fixup(newnode); | |
} | |
} | |
void RB_Insert_Fixup(node* z) { | |
while(z->parent->color == "RED") { | |
auto grandparent = z->parent->parent; | |
auto uncle = GetRoot(); | |
if(z->parent == grandparent->left) { | |
if(grandparent->right) { uncle = grandparent->right; } | |
if(uncle->color == "RED"){ | |
z->parent->color = "BLACK"; | |
uncle->color = "BLACK"; | |
grandparent->color = "RED"; | |
if(grandparent->data != root->data){ z = grandparent; } | |
else { break; } | |
} | |
else if(z == grandparent->left->right) { | |
LeftRotate(z->parent); | |
} | |
else { | |
z->parent->color = "BLACK"; | |
grandparent->color = "RED"; | |
RightRotate(grandparent); | |
if(grandparent->data != root->data){ z = grandparent; } | |
else { break; } | |
} | |
} | |
else { | |
if(grandparent->left) { uncle = grandparent->left; } | |
if(uncle->color == "RED"){ | |
z->parent->color = "BLACK"; | |
uncle->color = "BLACK"; | |
grandparent->color = "RED"; | |
if(grandparent->data != root->data){ z = grandparent; } | |
else { break; } | |
} | |
else if(z == grandparent->right->left){ | |
RightRotate(z->parent); | |
} | |
else { | |
z->parent->color = "BLACK"; | |
grandparent->color = "RED"; | |
LeftRotate(grandparent); | |
if(grandparent->data != root->data){ z = grandparent; } | |
else { break; } | |
} | |
} | |
} | |
root->color = "BLACK"; | |
} | |
void RemoveNode(node* parent, node* curr, int stuff) { | |
if(curr == nullptr) { return; } | |
if(curr->data == stuff) { | |
//CASE -- 1 | |
if(curr->left == nullptr && curr->right == nullptr) { | |
if(parent->data == curr->data){ root = nullptr; } | |
else if(parent->right == curr) { | |
RB_Delete_Fixup(curr); | |
parent->right = nullptr; | |
} | |
else { | |
RB_Delete_Fixup(curr); | |
parent->left = nullptr; | |
} | |
} | |
//CASE -- 2 | |
else if(curr->left != nullptr && curr->right == nullptr) { | |
int swap = curr->data; | |
curr->data = curr->left->data; | |
curr->left->data = swap; | |
RemoveNode(curr, curr->right, stuff); | |
} | |
else if(curr->left == nullptr && curr->right != nullptr) { | |
int swap = curr->data; | |
curr->data = curr->right->data; | |
curr->right->data = swap; | |
RemoveNode(curr, curr->right, stuff); | |
} | |
//CASE -- 3 | |
else { | |
bool flag = false; | |
node* temp = curr->right; | |
while(temp->left) { flag = true; parent = temp; temp = temp->left; } | |
if(!flag) { parent = curr; } | |
int swap = curr->data; | |
curr->data = temp->data; | |
temp->data = swap; | |
RemoveNode(parent, temp, swap); | |
} | |
} | |
} | |
void Remove(int stuff) { | |
auto temp = root; | |
auto parent = temp; | |
bool flag = false; | |
if(!temp) { RemoveNode(nullptr, nullptr, stuff); } | |
while(temp) { | |
if(stuff == temp->data) { flag = true; RemoveNode(parent, temp, stuff); break; } | |
else if(stuff < temp->data) { parent = temp ; temp = temp->left; } | |
else { parent = temp ; temp = temp->right; } | |
} | |
if(!flag) { cout << "\nElement doesn't exist in the table"; } | |
} | |
void RB_Delete_Fixup(node* z) { | |
while(z->data != root->data && z->color == "BLACK") { | |
auto sibling = GetRoot(); | |
if(z->parent->left == z) { | |
if(z->parent->right){ sibling = z->parent->right; } | |
if(sibling) { | |
//CASE -- 1 | |
if(sibling->color == "RED") { | |
sibling->color = "BLACK"; | |
z->parent->color = "RED"; | |
LeftRotate(z->parent); | |
sibling = z->parent->right; | |
} | |
//CASE -- 2 | |
if(sibling->left == nullptr && sibling->right == nullptr) { | |
sibling->color = "RED"; | |
z = z->parent; | |
} | |
else if(sibling->left->color == "BLACK" && sibling->right->color == "BLACK") { | |
sibling->color = "RED"; | |
z = z->parent; | |
} | |
//CASE -- 3 | |
else if(sibling->right->color == "BLACK") { | |
sibling->left->color = "BLACK"; | |
sibling->color = "RED"; | |
RightRotate(sibling); | |
sibling = z->parent->right; | |
} else { | |
sibling->color = z->parent->color; | |
z->parent->color = "BLACK"; | |
if(sibling->right){ sibling->right->color = "BLACK"; } | |
LeftRotate(z->parent); | |
z = root; | |
} | |
} | |
} else { | |
if(z->parent->right == z){ | |
if(z->parent->left){ sibling = z->parent->left; } | |
if(sibling) { | |
//CASE -- 1 | |
if(sibling->color == "RED"){ | |
sibling->color = "BLACK"; | |
z->parent->color = "RED"; | |
RightRotate(z->parent); | |
sibling = z->parent->left; | |
} | |
//CASE -- 2 | |
if(sibling->left == nullptr && sibling->right == nullptr) { | |
sibling->color = "RED"; | |
z = z->parent; | |
} | |
else if(sibling->left->color == "BLACK" && sibling->right->color == "BLACK") { | |
sibling->color = "RED"; | |
z = z->parent; | |
} | |
//CASE -- 3 | |
else if(sibling->left->color == "BLACK") { | |
sibling->right->color = "BLACK"; | |
sibling->color = "RED"; | |
RightRotate(sibling); | |
sibling = z->parent->left; | |
} else { | |
sibling->color = z->parent->color; | |
z->parent->color = "BLACK"; | |
if(sibling->left){ sibling->left->color = "BLACK"; } | |
LeftRotate(z->parent); | |
z = root; | |
} | |
} | |
} | |
} | |
} | |
z->color = "BLACK"; | |
} | |
node* TreeSearch(int stuff) { | |
auto temp = GetRoot(); | |
if(temp == nullptr) { return nullptr; } | |
while(temp) { | |
if(stuff == temp->data){ return temp; } | |
else if(stuff < temp->data){ temp = temp->left; } | |
else { temp = temp->right; } | |
} | |
return nullptr; | |
} | |
void LeftRotate(node* x) { | |
node* nw_node = new node(); | |
if(x->right->left) { nw_node->right = x->right->left; } | |
nw_node->left = x->left; | |
nw_node->data = x->data; | |
nw_node->color = x->color; | |
x->data = x->right->data; | |
x->left = nw_node; | |
if(nw_node->left){ nw_node->left->parent = nw_node; } | |
if(nw_node->right){ nw_node->right->parent = nw_node; } | |
nw_node->parent = x; | |
if(x->right->right){ x->right = x->right->right; } | |
else { x->right = nullptr; } | |
if(x->right){ x->right->parent = x; } | |
} | |
void RightRotate(node* x) { | |
node* nw_node = new node(); | |
if(x->left->right){ nw_node->left = x->left->right; } | |
nw_node->right = x->right; | |
nw_node->data = x->data; | |
nw_node->color = x->color; | |
x->data = x->left->data; | |
x->color = x->left->color; | |
x->right = nw_node; | |
if(nw_node->left){ nw_node->left->parent = nw_node; } | |
if(nw_node->right){ nw_node->right->parent = nw_node; } | |
nw_node->parent = x; | |
if(x->left->left){ x->left = x->left->left; } | |
else { x->left = nullptr; } | |
if(x->left){ x->left->parent = x; } | |
} | |
void PreorderTraversal(node* temp) { | |
if(!temp){ return; } | |
cout << "--> " << temp->data << "<" << temp->color << ">"; | |
PreorderTraversal(temp->left); | |
PreorderTraversal(temp->right); | |
} | |
void PostorderTraversal(node *temp) { | |
if(!temp){ return; } | |
PostorderTraversal(temp->left); | |
PostorderTraversal(temp->right); | |
cout << "--> " << temp->data << "<" << temp->color << ">"; | |
} | |
}; | |
void menu(){ | |
cout << "\n__________________________________________"; | |
cout << "\n\n --HEIGHT BALANCED BINARY SEARCH TREE--"; | |
cout << "\n --(Red-Black-Tree)--"; | |
cout << "\n__________________________________________"; | |
cout << "\n\n1. Insert elements into the tree."; | |
cout << "\n2. Search for an element."; | |
cout << "\n3. PRE-ORDER Tree-Walk."; | |
cout << "\n4. POST-ORDER Tree-Walk."; | |
cout << "\n5. Remove an element from the tree."; | |
cout << "\n6. Exit."; | |
cout << "\n__________________________________________"; | |
cout << "\nYour Choice -- "; | |
} | |
int main(){ | |
RB_TREE demo; | |
int info, input; | |
menu(); | |
cin >> info; | |
while(info != 6){ | |
switch (info){ | |
case 1: cout << "\nElement to be inserted -- "; | |
cin >> input; demo.InsertNode(input); | |
break; | |
case 2: cout << "\nElement to be searched -- "; | |
cin >> input; | |
if(demo.TreeSearch(input)) { cout << "Element found.\n"; } | |
else { cout << "Element not found.\n"; } | |
break; | |
case 3: cout << "Pre-Order Tree Walk "; | |
demo.PreorderTraversal(demo.GetRoot()); | |
cout << endl; | |
break; | |
case 4: cout << "Post-Order Tree Walk "; | |
demo.PostorderTraversal(demo.GetRoot()); | |
cout << endl; | |
break; | |
case 5: cout << "\nElement to be deleted? -- "; | |
cin >> input; | |
demo.Remove(input); | |
break; | |
default: cout << "Wrong Choice.\n"; | |
} | |
cout << "\nAnything Else?"; | |
cin >> info; | |
} | |
cout << "\nTerminating.... "; | |
return 0; | |
} |
i am confused in one thing if user enters 1 insert value in the tree but if users enters 7 it should read the file .
Seems good... easy to make so the color is bool or uint8_t. Just interested in the order lowest to highest so fiddled the output function. Been looking for a fast BPlus Tree but this seemed just as good and has the right output.
Need fast ability to sort scene elements in a game engine which at the moment is a binary tree that's suffering due to being unbalanced for ~1000 inserts. I will pre-allocate all the nodes at the start and instead of allocating all the time just pull them from a pool. Also... due to this allocation pruning the tree is as simple as resetting the root each time.
void InOrderTraversal(node* temp)
{
if(!temp)
{
return;
}
if (temp->left)
{
InOrderTraversal(temp->left);
printf(">%d%c\n", temp->data, (temp->color ? 'B' : 'R')) ;
}
else
{
printf(">%d%c\n", temp->data, (temp->color ? 'B' : 'R')) ;
}
if (temp->right)
{
InOrderTraversal(temp->right);
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also, on line 124 of the RemoveNode(...) method, since the idea here is to remove the left child of curr, shouldn't the recursive call be
RemoveNode(curr, curr->left, stuff);
instead of
RemoveNode(curr, curr->right, stuff);
?Thanks again!