From c87d433901c8d96b8427c7c27a2015e3c0039e18 Mon Sep 17 00:00:00 2001 From: Llewellyn van der Merwe Date: Sat, 21 Nov 2020 12:41:11 +0200 Subject: [PATCH] Week 12: Assignment - Red Black Trees --- week-12-1/CMakeLists.txt | 6 + week-12-1/main.cpp | 356 +++++++++++++++++++++++++++++++++++++++ week-12-2/CMakeLists.txt | 6 + week-12-2/main.cpp | 336 ++++++++++++++++++++++++++++++++++++ 4 files changed, 704 insertions(+) create mode 100644 week-12-1/CMakeLists.txt create mode 100644 week-12-1/main.cpp create mode 100644 week-12-2/CMakeLists.txt create mode 100644 week-12-2/main.cpp diff --git a/week-12-1/CMakeLists.txt b/week-12-1/CMakeLists.txt new file mode 100644 index 0000000..2d628ac --- /dev/null +++ b/week-12-1/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.16) +project(week-12-1) + +set(CMAKE_CXX_STANDARD 14) + +add_executable(week-12-1 main.cpp) diff --git a/week-12-1/main.cpp b/week-12-1/main.cpp new file mode 100644 index 0000000..3c17ab0 --- /dev/null +++ b/week-12-1/main.cpp @@ -0,0 +1,356 @@ +#include + +using namespace std; + +struct node { + int data{}; + node *left = nullptr; + node *right = nullptr; + node *parent = nullptr; + string color; +}; + +class tree { +private: + node *root; +public: + 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; } + } + + // display the tree + // Adapted from https://stackoverflow.com/a/51730733/1429677 + void display(const std::string &prefix, const node *node, bool isLeft) { + if (node != nullptr) { + // print the prefix + cout << prefix; + cout << (isLeft ? "├──" : "└──"); + // print the value of the node + if ("RED" == node->color){ + cout << "\033[1;31m" << node->data << "\033[0m" << endl; + } else { + cout << node->data << endl; + } + // enter the next tree level - left and right branch + display(prefix + (isLeft ? "│ " : " "), node->left, true); + display(prefix + (isLeft ? "│ " : " "), node->right, false); + } + } + +// display the binary tree + void display() { + display("", root, false); + } + + 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 << ">"; + } +}; + + +int main() { + // the empty tree + tree demo; + // lets load the values + demo.InsertNode(30); + demo.InsertNode(28); + demo.InsertNode(21); + demo.InsertNode(11); + demo.InsertNode(17); + demo.InsertNode(4); + demo.InsertNode(230); + demo.InsertNode(128); + demo.InsertNode(121); + demo.InsertNode(31); + demo.InsertNode(2); + demo.InsertNode(7); + // display the tree + demo.PreorderTraversal(demo.GetRoot()); + demo.display(); + + return 0; +} \ No newline at end of file diff --git a/week-12-2/CMakeLists.txt b/week-12-2/CMakeLists.txt new file mode 100644 index 0000000..d87d378 --- /dev/null +++ b/week-12-2/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.16) +project(week-12-2) + +set(CMAKE_CXX_STANDARD 14) + +add_executable(week-12-2 main.cpp) diff --git a/week-12-2/main.cpp b/week-12-2/main.cpp new file mode 100644 index 0000000..b255ec0 --- /dev/null +++ b/week-12-2/main.cpp @@ -0,0 +1,336 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-345-81 + * + * C++ Week 12: Red Black Binary Trees (first semester) - (2020/11/27) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Given an initially empty red black tree, write code to insert the following keys (30,28,21,11,17,4). + * Include your source code, output and a color-coded diagram of the tree. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , November 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/** Taken from geeksforgeeks + https://www.geeksforgeeks.org/c-program-red-black-tree-insertion/ + Adapted by Llewellyn van der Merwe **/ + + /** C++ implementation for + Red-Black Tree Insertion + This code is adopted from + the code provided by + Dinesh Khandelwal in comments **/ + +#include + +using namespace std; + +enum Color { + RED, BLACK +}; + +struct Node { + int data; + bool color; + Node *left, *right, *parent; + + // Constructor + Node(int data) { + this->data = data; + left = right = parent = nullptr; + this->color = RED; + } +}; + +// Class to represent Red-Black Tree +class RBTree { +private: + Node *root; +protected: + void rotateLeft(Node *&, Node *&); + + void rotateRight(Node *&, Node *&); + + void fixViolation(Node *&, Node *&); + +public: + // Constructor + RBTree() { root = nullptr; } + + void insert(const int &n); + + void inorder(); + + void levelOrder(); + + void display(); +}; + +// color printing helper +string printColorHelper(Node *root) { + // check the color + if (RED == root->color) { + // red background with white number + return "\033[1;41;37m " + to_string(root->data) + " \033[0m"; + } else { + // black background with white number + return "\033[1;40;37m " + to_string(root->data) + " \033[0m"; + } +} + +// A recursive function to do inorder traversal +void inorderHelper(Node *root) { + if (root == nullptr) + return; + + inorderHelper(root->left); + cout << printColorHelper(root) << " "; + inorderHelper(root->right); +} + +// display the tree +// Adapted from https://stackoverflow.com/a/51730733/1429677 +void displayHelper(const std::string &prefix, Node *node, bool isLeft) { + if (node != nullptr) { + // print the prefix + cout << prefix; + cout << (isLeft ? "├──" : "└──"); + // print the value of the node + cout << printColorHelper(node) << endl; + // enter the next tree level - left and right branch + displayHelper(prefix + (isLeft ? "│ " : " "), node->left, true); + displayHelper(prefix + (isLeft ? "│ " : " "), node->right, false); + } +} + +/* A utility function to insert + a new node with given key + in BST */ +Node *BSTInsert(Node *root, Node *pt) { + /* If the tree is empty, return a new node */ + if (root == NULL) + return pt; + + /* Otherwise, recur down the tree */ + if (pt->data < root->data) { + root->left = BSTInsert(root->left, pt); + root->left->parent = root; + } else if (pt->data > root->data) { + root->right = BSTInsert(root->right, pt); + root->right->parent = root; + } + + /* return the (unchanged) node pointer */ + return root; +} + +// Utility function to do level order traversal +void levelOrderHelper(Node *root) { + if (root == NULL) + return; + + std::queue q; + q.push(root); + + while (!q.empty()) { + Node *temp = q.front(); + cout << printColorHelper(temp) << " "; + q.pop(); + + if (temp->left != NULL) + q.push(temp->left); + + if (temp->right != NULL) + q.push(temp->right); + } +} + +void RBTree::rotateLeft(Node *&root, Node *&pt) { + Node *pt_right = pt->right; + + pt->right = pt_right->left; + + if (pt->right != NULL) + pt->right->parent = pt; + + pt_right->parent = pt->parent; + + if (pt->parent == NULL) + root = pt_right; + + else if (pt == pt->parent->left) + pt->parent->left = pt_right; + + else + pt->parent->right = pt_right; + + pt_right->left = pt; + pt->parent = pt_right; +} + +void RBTree::rotateRight(Node *&root, Node *&pt) { + Node *pt_left = pt->left; + + pt->left = pt_left->right; + + if (pt->left != NULL) + pt->left->parent = pt; + + pt_left->parent = pt->parent; + + if (pt->parent == NULL) + root = pt_left; + + else if (pt == pt->parent->left) + pt->parent->left = pt_left; + + else + pt->parent->right = pt_left; + + pt_left->right = pt; + pt->parent = pt_left; +} + +// This function fixes violations +// caused by BST insertion +void RBTree::fixViolation(Node *&root, Node *&pt) { + Node *parent_pt = NULL; + Node *grand_parent_pt = NULL; + + while ((pt != root) && (pt->color != BLACK) && + (pt->parent->color == RED)) { + + parent_pt = pt->parent; + grand_parent_pt = pt->parent->parent; + + /* Case : A + Parent of pt is left child + of Grand-parent of pt */ + if (parent_pt == grand_parent_pt->left) { + + Node *uncle_pt = grand_parent_pt->right; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if (uncle_pt != NULL && uncle_pt->color == RED) { + grand_parent_pt->color = RED; + parent_pt->color = BLACK; + uncle_pt->color = BLACK; + pt = grand_parent_pt; + } else { + /* Case : 2 + pt is right child of its parent + Left-rotation required */ + if (pt == parent_pt->right) { + rotateLeft(root, parent_pt); + pt = parent_pt; + parent_pt = pt->parent; + } + + /* Case : 3 + pt is left child of its parent + Right-rotation required */ + rotateRight(root, grand_parent_pt); + swap(parent_pt->color, + grand_parent_pt->color); + pt = parent_pt; + } + } + + /* Case : B + Parent of pt is right child + of Grand-parent of pt */ + else { + Node *uncle_pt = grand_parent_pt->left; + + /* Case : 1 + The uncle of pt is also red + Only Recoloring required */ + if ((uncle_pt != NULL) && (uncle_pt->color == RED)) { + grand_parent_pt->color = RED; + parent_pt->color = BLACK; + uncle_pt->color = BLACK; + pt = grand_parent_pt; + } else { + /* Case : 2 + pt is left child of its parent + Right-rotation required */ + if (pt == parent_pt->left) { + rotateRight(root, parent_pt); + pt = parent_pt; + parent_pt = pt->parent; + } + + /* Case : 3 + pt is right child of its parent + Left-rotation required */ + rotateLeft(root, grand_parent_pt); + swap(parent_pt->color, + grand_parent_pt->color); + pt = parent_pt; + } + } + } + + root->color = BLACK; +} + +// Function to insert a new node with given data +void RBTree::insert(const int &data) { + Node *pt = new Node(data); + // Do a normal BST insert + root = BSTInsert(root, pt); + + // fix Red Black Tree violations + fixViolation(root, pt); +} + +// Function to do inorder and level order traversals +void RBTree::inorder() { inorderHelper(root); } + +void RBTree::levelOrder() { levelOrderHelper(root); } + +// display the binary tree +void RBTree::display() { displayHelper("", root, false); } + +// Driver Code +int main() { + // empty tree + RBTree tree; + + // lets load the values + tree.insert(30); + tree.insert(28); + tree.insert(21); + tree.insert(11); + tree.insert(17); + tree.insert(4); + + cout << endl; + // show the color code + cout << "Color Code" << endl; + cout << "\033[1;40;37m BLACK \033[0m" << endl; + cout << "\033[1;41;37m RED \033[0m" << endl; + cout << endl; + // show inorder traversal + cout << "Inoder Traversal of Created Tree" << endl; + tree.inorder(); + cout << endl; + cout << endl; + // show level order traversal + cout << "Level Order Traversal of Created Tree" << endl; + tree.levelOrder(); + cout << endl; + cout << endl; + // show the tree + cout << "Display Tree" << endl; + tree.display(); + cout << endl; + return 0; +}