From 8370fa19f15ef73e3b064d73d9e69b42379906a6 Mon Sep 17 00:00:00 2001 From: TriantaTV Date: Sun, 5 Mar 2023 23:13:34 -0600 Subject: [PATCH] Why are the unique pointers annoying to use --- include/trees.hpp | 70 ++++++++---- src/trees.cpp | 278 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 298 insertions(+), 50 deletions(-) diff --git a/include/trees.hpp b/include/trees.hpp index cd22ad4..ff6afee 100644 --- a/include/trees.hpp +++ b/include/trees.hpp @@ -1,37 +1,69 @@ #ifndef TREES_HPP #define TREES_HPP +#include #include #include // Namespace for different implementations of trees namespace tree_implementation { - // Base Tree class - class Tree + // General nodes for Tree + struct TreeNode + { + std::string key; + std::string color; + std::unique_ptr leftChild; + std::unique_ptr rightChild; + std::unique_ptr parent; + TreeNode(std::string word); + ~TreeNode(void); + TreeNode(const TreeNode& rhs); + TreeNode& operator=(const TreeNode& rhs); + }; + + // General list for Tree + class TreeList { public: - Tree(void); - void Insert(void); - void Search(void); - void InOrderTreeTraversal(void); + std::unique_ptr head; + TreeList(void); + void InsertAtStart(std::string word); + void InsertAtEnd(std::string word); + void InsertAtPosition(std::string word); + void Remove(std::string word); + void Print(void); protected: - virtual void PrintParentKey(std::string key) = 0; - virtual void PrintLeftChild(std::string key) = 0; - virtual void PrintRightChild(std::string key) = 0; - virtual void PrintPathToRoot(std::string key) = 0; + ; private: ; }; - // Binary Search Tree operations - // TODO: Implement BST - class BinarySearchTree : public Tree + // Base Tree class + class TreeInterface { public: + TreeList tree; + TreeInterface(void); + TreeNode* Search(std::string wordToFind); + bool IsSearchSuccessful(std::unique_ptr foundNode); + void InOrderTreeTraversal(std::unique_ptr viewedNode); void PrintParentKey(std::string key); void PrintLeftChild(std::string key); void PrintRightChild(std::string key); + protected: + virtual void Insert(std::unique_ptr z); + virtual void PrintPathToRoot(std::string key) = 0; + private: + TreeNode* Insert(std::unique_ptr root, std::unique_ptr newNode); + TreeNode* Search(std::unique_ptr viewedNode, std::string wordToFind); + }; + + // Binary Search Tree operations + class BinarySearchTree : public TreeInterface + { + public: + void Insert(std::string keyToInsert); void PrintPathToRoot(std::string key); protected: ; @@ -40,13 +72,10 @@ namespace tree_implementation }; // Red-Black Tree operations - // TODO: Implement Red-black tree - class RedBlackTree : public Tree + class RedBlackTree : public TreeInterface { public: - void PrintParentKey(std::string key); - void PrintLeftChild(std::string key); - void PrintRightChild(std::string key); + void Insert(std::string keyToInsert); void PrintPathToRoot(std::string key); void PrintColor(std::string key); void PrintParentColor(std::string key); @@ -54,7 +83,10 @@ namespace tree_implementation protected: ; private: - ; + void InsertFixup(std::unique_ptr z); + std::unique_ptr GetUncleNode(std::unique_ptr startNode); + void LeftRotate(std::unique_ptr x); + void RightRotate(std::unique_ptr x); }; } diff --git a/src/trees.cpp b/src/trees.cpp index 7b2f837..0d401a5 100644 --- a/src/trees.cpp +++ b/src/trees.cpp @@ -1,81 +1,297 @@ #include "trees.hpp" +#include +#include #include #include namespace tree_implementation { - Tree::Tree(void) + + TreeNode::TreeNode(std::string word) { - ; + key = word; + color = "red"; + leftChild = nullptr; + rightChild = nullptr; + this->parent = nullptr; + return; } - void Tree::Insert(void) + TreeNode::~TreeNode(void) { - ; + return; + } + + TreeNode::TreeNode(const TreeNode& rhs) + { + key = rhs.key; + color = rhs.color; + return; } - void Tree::Search(void) + TreeNode& TreeNode::operator=(const TreeNode& rhs) { - ; + key = rhs.key; + color = rhs.color; + return *this; } - void Tree::InOrderTreeTraversal(void) + + TreeList::TreeList(void) { - ; + head = nullptr; + return; } - void BinarySearchTree::PrintParentKey(std::string key) + TreeInterface::TreeInterface(void) { - ; + return; } - void BinarySearchTree::PrintLeftChild(std::string key) + // Inserts a node into a BST + void TreeInterface::Insert(std::unique_ptr z) { - ; + std::unique_ptr y(nullptr); + std::unique_ptr x(tree.head.release()); + while (x) + { + y = x.release(); + if (z->key < x->key) + x = x->leftChild.release(); + else + x = x->rightChild.release(); + } + z->parent = y.release(); + if (!y) + tree.head = z.release(); + else if (z->key < y->key) + y->leftChild = z.release(); + else + y->rightChild = z.release(); + return; } - void BinarySearchTree::PrintRightChild(std::string key) + // Searches for the given word in a tree + TreeNode* TreeInterface::Search(std::string wordToFind) { - ; + return _Search(tree.head, wordToFind); } + bool IsSearchSuccessful(std::unique_ptr foundNode) + { + if (foundNode) + return true; + std::cout << "No node found with key '" << foundNode->key << "'\n"; + return false; + } + + // Prints tree while traversing it + void TreeInterface::InOrderTreeTraversal(std::unique_ptr viewedNode) + { + if (viewedNode) + InOrderTreeTraversal(viewedNode->leftChild); + std::cout << viewedNode.key << '\n'; + InOrderTreeTraversal(viewedNode->rightChild); + return; + } + + // Prints the given word's parent's word if found + void TreeInterface::PrintParentKey(std::string key) + { + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The parent's word is " << foundNode->parent->key << '\n'; + return; + } + + // Prints the given word's left child's word if found + void TreeInterface::PrintLeftChild(std::string key) + { + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The left child's word is " << foundNode->leftChild->key << '\n'; + return; + } + + // Prints the given word's right child's word if found + void TreeInterface::PrintRightChild(std::string key) + { + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The right child's word is " << foundNode->rightChild->key << '\n'; + return; + } + + // Recursive insertion function for Insert() + TreeNode* TreeInterface::Insert(std::unique_ptr root, std::unique_ptr newNode) + { + if (!tree.head) + return newNode.release(); + if (newNode->key < root->key) + { + root->leftChild = _Insert(root->leftChild, newNode); + root->leftChild->parent = root.release(); + } else if (newNode->key > root->key) { + root->rightChild = _Insert(root->rightChild, newNode); + root->rightChild->parent = root.release(); + } + return root.release(); + } + + // Recursive search function for Search() + TreeNode* TreeInterface::Search(std::unique_ptr viewedNode, std::string wordToFind) + { + if ((!viewedNode) || (wordToFind == viewedNode->key)) + return viewedNode.release(); + if (wordToFind < viewedNode->key) + return _Search(viewedNode->leftChild, wordToFind); + return _Search(viewedNode->rightChild, wordToFind); + } + + // Insert a node into a BST + void RedBlackTree::Insert(std::string keyToInsert) + { + std::unique_ptr newNode = new TreeNode(keyToInsert); + TreeInterface::Insert(newNode); + return; + } + + // Prints the path to root in a BST + // TODO: Implement printing path to root for BST void BinarySearchTree::PrintPathToRoot(std::string key) { - ; + std::unique_ptr selectedNode = std::move(Search(key)); + if (!IsSearchSuccessful(selectedNode)) return; + int timesPrintedOnLine = 0; + std::cout << "Path:\n" << selectedNode->key; + do + { + selectedNode = selectedNode->parent; + std::cout << " -> " << selectedNode->parent->key; + if (timesPrintedOnLine < 10) ++timesPrintedOnLine; + else std::cout << "\n"; + } while (selectedNode->parent); + + return; } - void RedBlackTree::PrintParentKey(std::string key) + // Insert a node into a RBT + void RedBlackTree::Insert(std::string keyToInsert) { - ; - } - - void RedBlackTree::PrintLeftChild(std::string key) - { - ; - } - - void RedBlackTree::PrintRightChild(std::string key) - { - ; + std::unique_ptr newNode = new TreeNode(keyToInsert); + TreeInterface::Insert(newNode); + InsertFixup(newNode); + return; } + // Print path to root in RBT + // TODO: Implement printing path to root for RBT void RedBlackTree::PrintPathToRoot(std::string key) { - ; + return; } + // Print color of word if found in RBT void RedBlackTree::PrintColor(std::string key) { - ; + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The color is " << foundNode->color << '\n'; + return; } + // Print color of word's parent if found in RBT void RedBlackTree::PrintParentColor(std::string key) { - ; + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The color is " << foundNode->parent->color << '\n'; + return; } + // Print color of word's uncle if found in RBT void RedBlackTree::PrintUncleColor(std::string key) { - ; + std::unique_ptr foundNode = std::move(Search(key)); + if (!IsSearchSuccessful(foundNode)) return; + std::cout << "The color is " << GetUncleNode(foundNode)->color << '\n'; + return; + } + + void RedBlackTree::InsertFixup(std::unique_ptr z) + { + std::unique_ptr y; + while (z->parent->color == "red") + { + if (z->parent == z->parent->parent->leftChild) + { + y = std::move(z->parent->parent->rightChild); + if (y->color == "red") + { + z->parent->color = "black"; + y->color = "black"; + z->parent->parent->color = "red"; + z = std::move(z->parent->parent); + } else if (z == z->parent->rightChild) { + z = std::move(z->parent); + LeftRotate(z); + z->parent->color = "black"; + z->parent->parent->color = "red"; + RightRotate(z->parent->parent); + } + } else { + // same as then clause with "right" and "left" exchanged + // TODO: Add else statement + ; + } + } + tree.head->color = "black"; + return; + } + + // Returns the uncle node in RBT + std::unique_ptr RedBlackTree::GetUncleNode(std::unique_ptr startNode) + { + if (startNode->parent == startNode->parent->parent->leftChild) + return std::move(startNode->parent->parent->rightChild); + return std::move(startNode->parent->parent->leftChild); + } + + // Performs left rotate on a given node + void RedBlackTree::LeftRotate(std::unique_ptr x) + { + std::unique_ptr y(std::move(x->rightChild)); + x->rightChild = std::move(y->leftChild); + if (y->rightChild) + y->rightChild->parent = std::move(x); + y->parent = std::move(x->parent); + if (!x->parent) + tree.head = std::move(y); + else if (x == x->parent->leftChild) + x->parent->leftChild = std::move(y); + else + x->parent->rightChild = std::move(y); + y->leftChild = std::move(x); + x->parent = std::move(y); + return; + } + + // Performs right rotate on a given node + void RedBlackTree::RightRotate(std::unique_ptr x) + { + std::unique_ptr y(std::move(x->rightChild)); + x->rightChild = std::move(y->leftChild); + if (y->leftChild) + y->leftChild->parent = std::move(x); + y->parent = std::move(x->parent); + if (!x->parent) + tree.head = std::move(y); + else if (x == x->parent->leftChild) + x->parent->leftChild = std::move(y); + else + x->parent->rightChild = std::move(y); + y->leftChild = std::move(x); + x->parent = std::move(y); + return; } } \ No newline at end of file