Update datastructs/binarysearchtree example

+ Utilize copy-swap idiom, miscellaneous clean-up of conditions and return values
This commit is contained in:
Shaun Reed 2021-06-09 11:00:02 -04:00
parent a8b6627135
commit 8f211b1603
4 changed files with 177 additions and 173 deletions

View File

@ -8,9 +8,14 @@
# #
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
# Define the project name project (
project(BinarySearchTree) #[[NAME]] BinaryTree
# Define source files VERSION 1.0
set(SRC driver.cpp bst.cpp) DESCRIPTION "A project for testing a basic implementation of a BST"
# Build an executable LANGUAGES CXX
add_executable(BSTDriver ${SRC}) )
add_library(lib-bst "bst.cpp")
add_executable(test-bst "driver.cpp")
target_link_libraries(test-bst lib-bst)

View File

@ -1,10 +1,10 @@
/*############################################################################# /*##############################################################################
## Author: Shaun Reed ## ## Author: Shaun Reed ##
## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## ## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a binary search tree implementation ## ## About: An example of a binary search tree implementation ##
## ## ## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
############################################################################## ################################################################################
## bst.cpp ## bst.cpp
*/ */
@ -21,27 +21,17 @@
* @param rhs The BST to copy, beginning from its root BinaryNode * @param rhs The BST to copy, beginning from its root BinaryNode
* @return const BinarySearchTree& The copied BinarySearchTree object * @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 the objects are already equal, do nothing
if (this == &rhs) return *this; if (this == &rhs) return *this;
// Empty this->root // Empty this->root
makeEmpty(); makeEmpty();
// Copy rhs to this->root std::swap(root, rhs.root);
root = clone(rhs.root);
return *this; return *this;
} }
/** Default Destructor
* @brief Destroy the Binary Search Tree:: Binary Search Tree object
*/
BinarySearchTree::~BinarySearchTree()
{
makeEmpty(root);
}
/******************************************************************************** /********************************************************************************
* Public Member Functions * 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 * @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 /** 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 * @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 /** contains
@ -84,12 +74,12 @@ bool BinarySearchTree::contains(const int &x) const
/** isEmpty /** isEmpty
* @brief Determine whether or not the calling BST object is empty * @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 * @return false If this->root node points to a constructed BinaryNode
*/ */
bool BinarySearchTree::isEmpty() const bool BinarySearchTree::isEmpty() const
{ {
return root == NULL; return root == nullptr;
} }
/** insert /** insert
@ -167,7 +157,7 @@ void BinarySearchTree::printPreOrder() const
BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *t) const BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *t) const
{ {
// If there is nothing to copy // 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 // Construct all child nodes through recursion, return root node
return new BinaryNode(t->element, clone(t->left), clone(t->right)); 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 void BinarySearchTree::insert(const int &x, BinarySearchTree::BinaryNode *&t) const
{ {
if (t == NULL) if (t == nullptr) t = new BinaryNode(x, nullptr, nullptr);
t = new BinaryNode(x, NULL, NULL); else if (x < t->element) insert (x, t->left);
else if (x < t->element) else if (x > t->element) insert (x, t->right);
insert (x, t->left); else return;
else if (x > t->element)
insert (x, t->right);
else
return;
} }
/** remove /** 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 void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) const
{ {
if (t == NULL) if (t == nullptr) return;
return;
if (x < t->element) if (x < t->element) remove(x, t->left);
remove(x, t->left); else if (x > t->element) remove(x, t->right);
else if (x > t->element) else if (t->left != nullptr && t->right != nullptr) {
remove(x, t->right);
else if (t->left != NULL && t->right != NULL) {
// If we found the node and there are two branches // If we found the node and there are two branches
t->element = findMin(t->right)->element; t->element = findMin(t->right)->element;
std::cout << "Removing [" << t->element << "]...\n"; std::cout << "Removing [" << t->element << "]...\n";
@ -215,7 +198,7 @@ void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) co
else { else {
// If we found the value and there is only one branch // If we found the value and there is only one branch
BinaryNode *oldNode = t; 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"; std::cout << "Removing [" << oldNode->element << "]...\n";
delete oldNode; 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 * @brief Find the minimum value within the BST of the given BinaryNode
* *
* @param t The root BinaryNode to begin checking values * @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 BinarySearchTree::BinaryNode * BinarySearchTree::findMin(BinarySearchTree::BinaryNode *t) const
{ {
while (t != NULL)
t = t->left;
// If our tree is empty // If our tree is empty
if (t == NULL) if (t == nullptr) return nullptr;
return NULL;
// If current node has no smaller children, it is min while (t->left != nullptr) t = t->left;
if (t->left == NULL)
return t;
// Move down the left side of our tree and check again return t;
return findMin(t->left);
} }
/** findMax /** findMax
* @brief Find the maximum value within the BST of the given BinaryNode * @brief Find the maximum value within the BST of the given BinaryNode
* *
* @param t The root BinaryNode to begin checking values * @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 BinarySearchTree::BinaryNode * BinarySearchTree::findMax(BinarySearchTree::BinaryNode *t) const
{ {
// If our tree is empty // If our tree is empty
if (t == NULL) if (t == nullptr) return nullptr;
return NULL;
// If current node has no larger children, it is max // If current node has no larger children, it is max
if (t->right == NULL) if (t->right == nullptr) return t;
return t;
// Move down the right side of our tree and check again // Move down the right side of our tree and check again
return findMax(t->right); return findMax(t->right);
@ -274,14 +249,13 @@ BinarySearchTree::BinaryNode * BinarySearchTree::findMax(BinarySearchTree::Binar
*/ */
bool BinarySearchTree::contains(const int &x, BinarySearchTree::BinaryNode *t) const bool BinarySearchTree::contains(const int &x, BinarySearchTree::BinaryNode *t) const
{ {
if (t == NULL) // If tree is empty // If tree is empty
return false; if (t == nullptr) return false;
else if (x < t->element) // If x is smaller than our current value // If x is smaller than our current value
return contains(x, t->left);// Check left node else if (x < t->element) return contains(x, t->left);
else if (x > t->element) // If x is larger than our current value // If x is larger than our current value, check the right node
return contains(x, t->right); // Check right node else if (x > t->element) return contains(x, t->right);
else else return true;
return true;
} }
/** makeEmpty /** makeEmpty
@ -291,12 +265,12 @@ bool BinarySearchTree::contains(const int &x, BinarySearchTree::BinaryNode *t) c
*/ */
void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t) void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t)
{ {
if (t != NULL) { if (t != nullptr) {
makeEmpty(t->left); makeEmpty(t->left);
makeEmpty(t->right); makeEmpty(t->right);
delete t; delete t;
} }
t = NULL; t = nullptr;
} }
/** printInOrder /** printInOrder
@ -306,7 +280,7 @@ void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t)
*/ */
void BinarySearchTree::printInOrder(BinaryNode *t) const void BinarySearchTree::printInOrder(BinaryNode *t) const
{ {
if(t != NULL) { if(t != nullptr) {
printInOrder(t->left); printInOrder(t->left);
std::cout << t->element << " "; std::cout << t->element << " ";
printInOrder(t->right); printInOrder(t->right);
@ -320,7 +294,7 @@ void BinarySearchTree::printInOrder(BinaryNode *t) const
*/ */
void BinarySearchTree::printPostOrder(BinaryNode *t) const void BinarySearchTree::printPostOrder(BinaryNode *t) const
{ {
if (t != NULL) { if (t != nullptr) {
printPostOrder(t->left); printPostOrder(t->left);
printPostOrder(t->right); printPostOrder(t->right);
std::cout << t->element << " "; std::cout << t->element << " ";
@ -328,13 +302,13 @@ void BinarySearchTree::printPostOrder(BinaryNode *t) const
} }
/** printPreOrder /** 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 * @param t The root BinaryNode to begin the 'Pre Order' output
*/ */
void BinarySearchTree::printPreOrder(BinaryNode *t) const void BinarySearchTree::printPreOrder(BinaryNode *t) const
{ {
if (t != NULL) { if (t != nullptr) {
std::cout << t->element << " "; std::cout << t->element << " ";
printPreOrder(t->left); printPreOrder(t->left);
printPreOrder(t->right); printPreOrder(t->right);

View File

@ -1,10 +1,10 @@
/*############################################################################# /*##############################################################################
## Author: Shaun Reed ## ## Author: Shaun Reed ##
## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## ## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a binary search tree implementation ## ## About: An example of a binary search tree implementation ##
## ## ## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
############################################################################## ################################################################################
## bst.h ## bst.h
*/ */
@ -16,41 +16,42 @@
// TODO: Add balance() method to balance overweight branches // TODO: Add balance() method to balance overweight branches
class BinarySearchTree { class BinarySearchTree {
public: public:
BinarySearchTree() : root(NULL) {}; BinarySearchTree() : root(nullptr) {};
BinarySearchTree(const BinarySearchTree &rhs) : root(rhs.clone(rhs.root)) {}; BinarySearchTree(const BinarySearchTree &rhs) : root(clone(rhs.root)) {};
const BinarySearchTree& operator=(const BinarySearchTree& rhs); BinarySearchTree& operator=(BinarySearchTree rhs);
~BinarySearchTree(); ~BinarySearchTree() { makeEmpty(root);};
const int & findMin() const; int findMin() const;
const int & findMax() const; int findMax() const;
bool contains(const int &x) const; bool contains(const int &x) const;
bool isEmpty() const; bool isEmpty() const;
void insert(const int &x); void insert(const int &x);
void remove(const int &x); void remove(const int &x);
void makeEmpty(); void makeEmpty();
void printInOrder() const; void printInOrder() const;
void printPostOrder() const; void printPostOrder() const;
void printPreOrder() const; void printPreOrder() const;
private: private:
struct BinaryNode{ struct BinaryNode{
int element; int element;
BinaryNode *left; BinaryNode *left;
BinaryNode *right; BinaryNode *right;
BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt) BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt)
:element(el), left(lt), right(rt) {}; :element(el), left(lt), right(rt) {};
}; };
BinaryNode *root; BinaryNode *root;
BinaryNode * clone(BinaryNode *t) const;
void insert(const int &x, BinaryNode *&t) const; BinaryNode * clone(BinaryNode *t) const;
void remove(const int &x, BinaryNode *&t) const; void insert(const int &x, BinaryNode *&t) const;
BinaryNode * findMin(BinaryNode *t) const; void remove(const int &x, BinaryNode *&t) const;
BinaryNode * findMax(BinaryNode *t) const; BinaryNode * findMin(BinaryNode *t) const;
bool contains(const int &x, BinaryNode *t) const; BinaryNode * findMax(BinaryNode *t) const;
void makeEmpty(BinaryNode * & t); bool contains(const int &x, BinaryNode *t) const;
void printInOrder(BinaryNode *t) const; void makeEmpty(BinaryNode * & t);
void printPostOrder(BinaryNode *t) const; void printInOrder(BinaryNode *t) const;
void printPreOrder(BinaryNode *t) const; void printPostOrder(BinaryNode *t) const;
void printPreOrder(BinaryNode *t) const;
}; };
#endif //BST_H #endif //BST_H

View File

@ -1,24 +1,26 @@
/*############################################################################# /*##############################################################################
## Author: Shaun Reed ## ## Author: Shaun Reed ##
## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ## ## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: A driver program to test a binary search tree implementation ## ## About: A driver program to test a binary search tree implementation ##
## ## ## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
############################################################################## ################################################################################
## driver.cpp ## driver.cpp
*/ */
#include "bst.h" #include "bst.h"
#include <iostream> #include <iostream>
enum OPS { 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() int main()
{ {
std::cout << "Driver: \n"; std::cout << "Driver: \n";
BinarySearchTree testList; BinarySearchTree testTree;
bool exit = false; bool exit = false;
int choice = -1; int choice = -1;
int val; int val;
@ -26,65 +28,87 @@ int main()
while (!exit) while (!exit)
{ {
std::cout << "##### Binary Search Tree Menu #####\n\t0. 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\t1. Insert\n\t2. Remove\n\t3. Contains\n\t4. In-order\n\t"
<< "\n\t6. Postfix\n\t7. Empty\n\t8. Min\n\t9. Max\n"; "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 >> choice;
std::cin.clear(); std::cin.clear();
switch (choice) { switch (choice) {
case EXIT: case EXIT:
exit = true; exit = true;
break; break;
case INSERT: case INSERT:
std::cout << "Enter a value to insert to our tree: "; std::cout << "Enter a value to insert to our tree: ";
std::cin >> val; std::cin >> val;
std::cin.clear(); std::cin.clear();
testList.insert(val); testTree.insert(val);
break; break;
case REMOVE: case REMOVE:
std::cout << "Enter a value to remove from our tree: "; std::cout << "Enter a value to remove from our tree: ";
std::cin >> val; std::cin >> val;
std::cin.clear(); std::cin.clear();
testList.remove(val); testTree.remove(val);
break; break;
case CONTAINS: case CONTAINS:
std::cout << "Enter a value to search for within our tree: "; std::cout << "Enter a value to search for within our tree: ";
std::cin >> val; std::cin >> val;
std::cin.clear(); std::cin.clear();
if (testList.contains(val)) if (testTree.contains(val)) std::cout << val << " exists in our tree\n";
std::cout << val << " exists within our tree\n"; else std::cout << val << " does not exist in our tree\n";
else std::cout << val << " does not exist within our tree\n"; break;
break;
case INFIX: case INFIX:
testList.printInOrder(); testTree.printInOrder();
break; break;
case PREFIX: case PREFIX:
testList.printPreOrder(); testTree.printPreOrder();
break; break;
case POSTFIX: case POSTFIX:
testList.printPostOrder(); testTree.printPostOrder();
break; break;
case EMPTY: case EMPTY:
testList.makeEmpty(); testTree.makeEmpty();
break; std::cout << "The BST is empty: "
<< (testTree.isEmpty() ? "true" : "false") << std::endl;
break;
case MIN: case MIN:
std::cout << "Min value within our tree: " << testList.findMin(); std::cout << "Min value within our tree: " << testTree.findMin() << "\n";
break; break;
case MAX: case MAX:
std::cout << "Max value within our tree: " << testList.findMax(); std::cout << "Max value within our tree: " << testTree.findMax() << "\n";
break; break;
default: case COPY:
std::cout << "Invalid entry...\n"; {
break; 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;
} }
} }
} }