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 hidden or 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; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The Insertion Algorithm
Nodes are always inserted as RED nodes at their designated BST position. If the parent node is black, no invariants are broken. If the parent node is red, it introduces a "Red-Red violation" that is fixed using three distinct cases depending on the color of the parent's sibling (the uncle node)