From 8f211b16032c0a5540bfd9cfdd418f143aa55214 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Wed, 9 Jun 2021 11:00:02 -0400 Subject: [PATCH] Update datastructs/binarysearchtree example + Utilize copy-swap idiom, miscellaneous clean-up of conditions and return values --- .../binarysearchtree/CMakeLists.txt | 17 ++- cpp/datastructs/binarysearchtree/bst.cpp | 116 ++++++--------- cpp/datastructs/binarysearchtree/bst.h | 83 +++++------ cpp/datastructs/binarysearchtree/driver.cpp | 134 +++++++++++------- 4 files changed, 177 insertions(+), 173 deletions(-) diff --git a/cpp/datastructs/binarysearchtree/CMakeLists.txt b/cpp/datastructs/binarysearchtree/CMakeLists.txt index 9f02739..e3a095d 100644 --- a/cpp/datastructs/binarysearchtree/CMakeLists.txt +++ b/cpp/datastructs/binarysearchtree/CMakeLists.txt @@ -8,9 +8,14 @@ # cmake_minimum_required(VERSION 3.15) -# Define the project name -project(BinarySearchTree) -# Define source files -set(SRC driver.cpp bst.cpp) -# Build an executable -add_executable(BSTDriver ${SRC}) +project ( + #[[NAME]] BinaryTree + VERSION 1.0 + DESCRIPTION "A project for testing a basic implementation of a BST" + LANGUAGES CXX +) + +add_library(lib-bst "bst.cpp") + +add_executable(test-bst "driver.cpp") +target_link_libraries(test-bst lib-bst) diff --git a/cpp/datastructs/binarysearchtree/bst.cpp b/cpp/datastructs/binarysearchtree/bst.cpp index 4c8a7db..32b590f 100644 --- a/cpp/datastructs/binarysearchtree/bst.cpp +++ b/cpp/datastructs/binarysearchtree/bst.cpp @@ -1,10 +1,10 @@ -/*############################################################################# -## Author: Shaun Reed ## -## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## -## About: An example of a binary search tree implementation ## -## ## -## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## -############################################################################## +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: An example of a binary search tree implementation ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ ## bst.cpp */ @@ -21,27 +21,17 @@ * @param rhs The BST to copy, beginning from its root BinaryNode * @return const BinarySearchTree& The copied BinarySearchTree object */ -const BinarySearchTree& BinarySearchTree::operator=(const BinarySearchTree& rhs) +BinarySearchTree& BinarySearchTree::operator=(BinarySearchTree rhs) { // If the objects are already equal, do nothing if (this == &rhs) return *this; // Empty this->root makeEmpty(); - // Copy rhs to this->root - root = clone(rhs.root); + std::swap(root, rhs.root); return *this; } -/** Default Destructor - * @brief Destroy the Binary Search Tree:: Binary Search Tree object - */ -BinarySearchTree::~BinarySearchTree() -{ - makeEmpty(root); -} - - /******************************************************************************** * Public Member Functions *********************************************************************************/ @@ -52,9 +42,9 @@ BinarySearchTree::~BinarySearchTree() * * @return const int& The element of the BinaryNode that holds the lowest value in our tree */ -const int & BinarySearchTree::findMin() const +int BinarySearchTree::findMin() const { - return findMin(root)->element; + return findMin(root) != nullptr ? findMin(root)->element: INT32_MIN; } /** findMax @@ -63,9 +53,9 @@ const int & BinarySearchTree::findMin() const * * @return const int& The element of the BinaryNode that holds the highest value in our tree */ -const int & BinarySearchTree::findMax() const +int BinarySearchTree::findMax() const { - return findMax(root)->element; + return findMax(root) != nullptr ? findMax(root)->element: INT32_MIN; } /** contains @@ -84,12 +74,12 @@ bool BinarySearchTree::contains(const int &x) const /** isEmpty * @brief Determine whether or not the calling BST object is empty * - * @return true If this->root node points to an empty tree (NULL) + * @return true If this->root node points to an empty tree (nullptr) * @return false If this->root node points to a constructed BinaryNode */ bool BinarySearchTree::isEmpty() const { - return root == NULL; + return root == nullptr; } /** insert @@ -167,7 +157,7 @@ void BinarySearchTree::printPreOrder() const BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *t) const { // If there is nothing to copy - if (t == NULL) return NULL; + if (t == nullptr) return nullptr; // Construct all child nodes through recursion, return root node return new BinaryNode(t->element, clone(t->left), clone(t->right)); @@ -181,14 +171,10 @@ BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *t) const */ void BinarySearchTree::insert(const int &x, BinarySearchTree::BinaryNode *&t) const { - if (t == NULL) - t = new BinaryNode(x, NULL, NULL); - else if (x < t->element) - insert (x, t->left); - else if (x > t->element) - insert (x, t->right); - else - return; + if (t == nullptr) t = new BinaryNode(x, nullptr, nullptr); + else if (x < t->element) insert (x, t->left); + else if (x > t->element) insert (x, t->right); + else return; } /** remove @@ -199,14 +185,11 @@ void BinarySearchTree::insert(const int &x, BinarySearchTree::BinaryNode *&t) co */ void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) const { - if (t == NULL) - return; + if (t == nullptr) return; - if (x < t->element) - remove(x, t->left); - else if (x > t->element) - remove(x, t->right); - else if (t->left != NULL && t->right != NULL) { + if (x < t->element) remove(x, t->left); + else if (x > t->element) remove(x, t->right); + else if (t->left != nullptr && t->right != nullptr) { // If we found the node and there are two branches t->element = findMin(t->right)->element; std::cout << "Removing [" << t->element << "]...\n"; @@ -215,7 +198,7 @@ void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) co else { // If we found the value and there is only one branch BinaryNode *oldNode = t; - t = (t->left != NULL) ? t->left : t->right; + t = (t->left != nullptr) ? t->left : t->right; std::cout << "Removing [" << oldNode->element << "]...\n"; delete oldNode; } @@ -225,40 +208,32 @@ void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) co * @brief Find the minimum value within the BST of the given BinaryNode * * @param t The root BinaryNode to begin checking values - * @return BinarySearchTree::BinaryNode* The BinaryNode which contains the smallest value (returns NULL if BST is empty) + * @return BinarySearchTree::BinaryNode* The BinaryNode which contains the smallest value (returns nullptr if BST is empty) */ BinarySearchTree::BinaryNode * BinarySearchTree::findMin(BinarySearchTree::BinaryNode *t) const { - while (t != NULL) - t = t->left; // If our tree is empty - if (t == NULL) - return NULL; + if (t == nullptr) return nullptr; - // If current node has no smaller children, it is min - if (t->left == NULL) - return t; + while (t->left != nullptr) t = t->left; - // Move down the left side of our tree and check again - return findMin(t->left); + return t; } /** findMax * @brief Find the maximum value within the BST of the given BinaryNode * * @param t The root BinaryNode to begin checking values - * @return BinarySearchTree::BinaryNode* The BinaryNode which contains the largest value (returns NULL if BST is empty) + * @return BinarySearchTree::BinaryNode* The BinaryNode which contains the largest value (returns nullptr if BST is empty) */ BinarySearchTree::BinaryNode * BinarySearchTree::findMax(BinarySearchTree::BinaryNode *t) const { // If our tree is empty - if (t == NULL) - return NULL; + if (t == nullptr) return nullptr; // If current node has no larger children, it is max - if (t->right == NULL) - return t; + if (t->right == nullptr) return t; // Move down the right side of our tree and check again return findMax(t->right); @@ -274,14 +249,13 @@ BinarySearchTree::BinaryNode * BinarySearchTree::findMax(BinarySearchTree::Binar */ bool BinarySearchTree::contains(const int &x, BinarySearchTree::BinaryNode *t) const { - if (t == NULL) // If tree is empty - return false; - else if (x < t->element) // If x is smaller than our current value - return contains(x, t->left);// Check left node - else if (x > t->element) // If x is larger than our current value - return contains(x, t->right); // Check right node - else - return true; + // If tree is empty + if (t == nullptr) return false; + // If x is smaller than our current value + else if (x < t->element) return contains(x, t->left); + // If x is larger than our current value, check the right node + else if (x > t->element) return contains(x, t->right); + else return true; } /** makeEmpty @@ -291,12 +265,12 @@ bool BinarySearchTree::contains(const int &x, BinarySearchTree::BinaryNode *t) c */ void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t) { - if (t != NULL) { + if (t != nullptr) { makeEmpty(t->left); makeEmpty(t->right); delete t; } - t = NULL; + t = nullptr; } /** printInOrder @@ -306,7 +280,7 @@ void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t) */ void BinarySearchTree::printInOrder(BinaryNode *t) const { - if(t != NULL) { + if(t != nullptr) { printInOrder(t->left); std::cout << t->element << " "; printInOrder(t->right); @@ -320,7 +294,7 @@ void BinarySearchTree::printInOrder(BinaryNode *t) const */ void BinarySearchTree::printPostOrder(BinaryNode *t) const { - if (t != NULL) { + if (t != nullptr) { printPostOrder(t->left); printPostOrder(t->right); std::cout << t->element << " "; @@ -328,13 +302,13 @@ void BinarySearchTree::printPostOrder(BinaryNode *t) const } /** printPreOrder - * @brief Output the value of the noot nodes before their subtrees + * @brief Output the value of the root nodes before their subtrees * * @param t The root BinaryNode to begin the 'Pre Order' output */ void BinarySearchTree::printPreOrder(BinaryNode *t) const { - if (t != NULL) { + if (t != nullptr) { std::cout << t->element << " "; printPreOrder(t->left); printPreOrder(t->right); diff --git a/cpp/datastructs/binarysearchtree/bst.h b/cpp/datastructs/binarysearchtree/bst.h index aa71e70..d016c98 100644 --- a/cpp/datastructs/binarysearchtree/bst.h +++ b/cpp/datastructs/binarysearchtree/bst.h @@ -1,10 +1,10 @@ -/*############################################################################# -## Author: Shaun Reed ## -## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## -## About: An example of a binary search tree implementation ## -## ## -## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## -############################################################################## +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: An example of a binary search tree implementation ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ ## bst.h */ @@ -16,41 +16,42 @@ // TODO: Add balance() method to balance overweight branches class BinarySearchTree { - public: - BinarySearchTree() : root(NULL) {}; - BinarySearchTree(const BinarySearchTree &rhs) : root(rhs.clone(rhs.root)) {}; - const BinarySearchTree& operator=(const BinarySearchTree& rhs); - ~BinarySearchTree(); - const int & findMin() const; - const int & findMax() const; - bool contains(const int &x) const; - bool isEmpty() const; - void insert(const int &x); - void remove(const int &x); - void makeEmpty(); - void printInOrder() const; - void printPostOrder() const; - void printPreOrder() const; +public: + BinarySearchTree() : root(nullptr) {}; + BinarySearchTree(const BinarySearchTree &rhs) : root(clone(rhs.root)) {}; + BinarySearchTree& operator=(BinarySearchTree rhs); + ~BinarySearchTree() { makeEmpty(root);}; + int findMin() const; + int findMax() const; + bool contains(const int &x) const; + bool isEmpty() const; + void insert(const int &x); + void remove(const int &x); + void makeEmpty(); + void printInOrder() const; + void printPostOrder() const; + void printPreOrder() const; - private: - struct BinaryNode{ - int element; - BinaryNode *left; - BinaryNode *right; - BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt) - :element(el), left(lt), right(rt) {}; - }; - BinaryNode *root; - BinaryNode * clone(BinaryNode *t) const; - void insert(const int &x, BinaryNode *&t) const; - void remove(const int &x, BinaryNode *&t) const; - BinaryNode * findMin(BinaryNode *t) const; - BinaryNode * findMax(BinaryNode *t) const; - bool contains(const int &x, BinaryNode *t) const; - void makeEmpty(BinaryNode * & t); - void printInOrder(BinaryNode *t) const; - void printPostOrder(BinaryNode *t) const; - void printPreOrder(BinaryNode *t) const; +private: + struct BinaryNode{ + int element; + BinaryNode *left; + BinaryNode *right; + BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt) + :element(el), left(lt), right(rt) {}; + }; + BinaryNode *root; + + BinaryNode * clone(BinaryNode *t) const; + void insert(const int &x, BinaryNode *&t) const; + void remove(const int &x, BinaryNode *&t) const; + BinaryNode * findMin(BinaryNode *t) const; + BinaryNode * findMax(BinaryNode *t) const; + bool contains(const int &x, BinaryNode *t) const; + void makeEmpty(BinaryNode * & t); + void printInOrder(BinaryNode *t) const; + void printPostOrder(BinaryNode *t) const; + void printPreOrder(BinaryNode *t) const; }; #endif //BST_H diff --git a/cpp/datastructs/binarysearchtree/driver.cpp b/cpp/datastructs/binarysearchtree/driver.cpp index f1c85f0..3d4c2f3 100644 --- a/cpp/datastructs/binarysearchtree/driver.cpp +++ b/cpp/datastructs/binarysearchtree/driver.cpp @@ -1,24 +1,26 @@ -/*############################################################################# -## Author: Shaun Reed ## -## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## -## About: A driver program to test a binary search tree implementation ## -## ## -## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## -############################################################################## +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: A driver program to test a binary search tree implementation ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ ## driver.cpp */ #include "bst.h" + #include enum OPS { - EXIT, INSERT, REMOVE, CONTAINS, INFIX, PREFIX, POSTFIX, EMPTY, MIN, MAX + EXIT, INSERT, REMOVE, CONTAINS, INFIX, PREFIX, POSTFIX, EMPTY, MIN, MAX, + COPY, EQUAL }; int main() { std::cout << "Driver: \n"; - BinarySearchTree testList; + BinarySearchTree testTree; bool exit = false; int choice = -1; int val; @@ -26,65 +28,87 @@ int main() while (!exit) { std::cout << "##### Binary Search Tree Menu #####\n\t0. Exit" - "\n\t1. Insert\n\t2. Remove\n\t3. Contains\n\t4. Infix\n\t5. Prefix" - << "\n\t6. Postfix\n\t7. Empty\n\t8. Min\n\t9. Max\n"; + "\n\t1. Insert\n\t2. Remove\n\t3. Contains\n\t4. In-order\n\t" + "5. Pre-order\n\t6. Post-order\n\t7. Empty\n\t8. Min\n\t9. Max" + "\n\t10. Copy BST\n\t11. Equal BST\n"; std::cin >> choice; std::cin.clear(); switch (choice) { - case EXIT: - exit = true; - break; + case EXIT: + exit = true; + break; - case INSERT: - std::cout << "Enter a value to insert to our tree: "; - std::cin >> val; - std::cin.clear(); - testList.insert(val); - break; + case INSERT: + std::cout << "Enter a value to insert to our tree: "; + std::cin >> val; + std::cin.clear(); + testTree.insert(val); + break; - case REMOVE: - std::cout << "Enter a value to remove from our tree: "; - std::cin >> val; - std::cin.clear(); - testList.remove(val); - break; + case REMOVE: + std::cout << "Enter a value to remove from our tree: "; + std::cin >> val; + std::cin.clear(); + testTree.remove(val); + break; - case CONTAINS: - std::cout << "Enter a value to search for within our tree: "; - std::cin >> val; - std::cin.clear(); - if (testList.contains(val)) - std::cout << val << " exists within our tree\n"; - else std::cout << val << " does not exist within our tree\n"; - break; + case CONTAINS: + std::cout << "Enter a value to search for within our tree: "; + std::cin >> val; + std::cin.clear(); + if (testTree.contains(val)) std::cout << val << " exists in our tree\n"; + else std::cout << val << " does not exist in our tree\n"; + break; - case INFIX: - testList.printInOrder(); - break; + case INFIX: + testTree.printInOrder(); + break; - case PREFIX: - testList.printPreOrder(); - break; + case PREFIX: + testTree.printPreOrder(); + break; - case POSTFIX: - testList.printPostOrder(); - break; + case POSTFIX: + testTree.printPostOrder(); + break; - case EMPTY: - testList.makeEmpty(); - break; + case EMPTY: + testTree.makeEmpty(); + std::cout << "The BST is empty: " + << (testTree.isEmpty() ? "true" : "false") << std::endl; + break; - case MIN: - std::cout << "Min value within our tree: " << testList.findMin(); - break; + case MIN: + std::cout << "Min value within our tree: " << testTree.findMin() << "\n"; + break; - case MAX: - std::cout << "Max value within our tree: " << testList.findMax(); - break; + case MAX: + std::cout << "Max value within our tree: " << testTree.findMax() << "\n"; + break; - default: - std::cout << "Invalid entry...\n"; - break; + case COPY: + { + BinarySearchTree copiedTree(testTree); + std::cout << "Inorder output from copied tree: "; + copiedTree.printInOrder(); + std::cout << std::endl; + // copiedTree calls destructor when leaving this scope + break; + } + + case EQUAL: { + BinarySearchTree equalTree; + equalTree = testTree; + std::cout << "Inorder output from equal tree: "; + equalTree.printInOrder(); + std::cout << std::endl; + // equalTree calls destructor when leaving this scope + break; + } + + default: + std::cout << "Invalid entry...\n"; + break; } } }