Add RD of Binary Search Tree implementation

+ Update .gitignore to exclude .idea configs
This commit is contained in:
Shaun Reed 2020-07-04 20:58:14 -04:00
parent b258c14022
commit a864342974
5 changed files with 504 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
build/
**/.vscode
**/.idea/**
**/driver
**/*.o
**/cmake-build-debug/**

View File

@ -0,0 +1,17 @@
###############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2020 Shaun Reed, all rights reserved ##
## About: A basic CMakeLists configuration to test BST implementation ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################
## vector.cpp
#
cmake_minimum_required(VERSION 3.2)
# Define the project name
project(BinarySearchTree)
# Define source files
set(SRC driver.cpp bst.cpp)
# Build an executable
add_executable(BSTDriver ${SRC})

View File

@ -0,0 +1,339 @@
/*#############################################################################
## 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 ##
##############################################################################
## bst.cpp
*/
#include "bst.h"
/********************************************************************************
* Constructors, Destructors, Operators
*********************************************************************************/
/** Default Destructor
* @brief Destroy the Binary Search Tree:: Binary Search Tree object
*/
BinarySearchTree::~BinarySearchTree()
{
makeEmpty(root);
}
/** Copy Assignment Operator
* @brief Empty the calling object's root BinaryNode, and copy the rhs data
*
* @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)
{
// 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);
return *this;
}
/********************************************************************************
* Public Member Functions
*********************************************************************************/
/** findMin
* @brief Find and return the minimum value of the calling BST object
* Calls to the private member findMin(BinaryNode* t)
*
* @return const int& The element of the BinaryNode that holds the lowest value in our tree
*/
const int & BinarySearchTree::findMin() const
{
return findMin(root)->element;
}
/** findMax
* @brief Find and return the maximum value of the calling BST object
* Calls to the private member findMax(BinaryNode* t)
*
* @return const int& The element of the BinaryNode that holds the highest value in our tree
*/
const int & BinarySearchTree::findMax() const
{
return findMax(root)->element;
}
/** contains
* @brief Determine whether or not a value exists within the calling BST object
* Calls to the private member contains(const int &x, BinaryNode* t)
*
* @param x The value to search for within our tree
* @return true If the value is found within any BinaryNode->element
* @return false If the value is not found within any BinaryNode->element
*/
bool BinarySearchTree::contains(const int &x) const
{
return contains(x, root);
}
/** isEmpty
* @brief Determine wheter or not the calling BST object is empty
*
* @return true If this->root node points to an empty tree (NULL)
* @return false If this->root node points to a constructed BinaryNode
*/
bool BinarySearchTree::isEmpty() // const?
{
return root == NULL;
}
/** insert
* @brief Inserts a new value into the calling BST object
* Calls to the private member insert(const int &x, BinaryNode* t)
*
* @param x The new value to insert into our BinarySearchTree
*/
void BinarySearchTree::insert(const int & x)
{
insert(x, root);
}
/** remove
* @brief Remove a value from the calling BST object
* Calls to the private member remove(const int &x, BinaryNode* t)
*
* @param x The value to remove from our BST
*/
void BinarySearchTree::remove(const int &x)
{
remove(x, root);
}
/** makeEmpty
* @brief Delete the root BinaryNode and all of its children from the calling BST object
* Calls to the private member makeEmpty(BinaryNode* t)
*/
void BinarySearchTree::makeEmpty()
{
makeEmpty(root);
}
/** printInOrder
* @brief Output the element of each BinaryNode between their left and right subtrees
* Calls to the private member printInOrder(BinaryNode* t)
*/
void BinarySearchTree::printInOrder() const
{
printInOrder(root);
}
/** printPostOrder
* @brief Output the element of each BinaryNode after their left and right subtrees
* Calls to the private member printPostOrder(BinaryNode* t)
*/
void BinarySearchTree::printPostOrder() const
{
printPostOrder(root);
}
/** printPreOrder
* @brief Output the element of each BinaryNode before their left and right subtrees
* Calls to the private member printPreOrder(BinaryNode* t)
*/
void BinarySearchTree::printPreOrder() const
{
printPreOrder(root);
}
/********************************************************************************
* Private Member Functions
*********************************************************************************/
/** clone
* @brief Clone a BST node and all its children
*
* @param t The node to begin cloning from
* @return BinarySearchTree::BinaryNode* The root node of the copied tree
*/
BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *t) const
{
// If there is nothing to copy
if (t == NULL) return NULL;
// Construct all child nodes through recursion, return root node
return new BinaryNode(t->element, clone(t->left), clone(t->right));
}
/** insert
* @brief Insert a value into the BST of the given BinaryNode
*
* @param x The value to be inserted
* @param t The BinaryNode to beign insertion
*/
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;
}
/** remove
* @brief Removes a value from the BST of the given BinaryNode
*
* @param x The value to be removed
* @param t The BinaryNode to begin search and removal from
*/
void BinarySearchTree::remove(const int &x, BinarySearchTree::BinaryNode *&t) const
{
if (t == NULL)
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 we found the node and there are two branches
t->element = findMin(t->right)->element;
std::cout << "Removing [" << t->element << "]...\n";
remove(t->element, t->right);
}
else {
// If we found the value and there is only one branch
BinaryNode *oldNode = t;
t = (t->left != NULL) ? t->left : t->right;
std::cout << "Removing [" << oldNode->element << "]...\n";
delete oldNode;
}
}
/** findMin
* @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)
*/
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 current node has no smaller children, it is min
if (t->left == NULL)
return t;
// Move down the left side of our tree and check again
return findMin(t->left);
}
/** findMax
* @brief Find the maximum value within the BST of the given BinaryNode
*
* @param t Te root BinaryNode to begin checking values
* @return BinarySearchTree::BinaryNode* The BinaryNode which contains the largest value (returns NULL if BST is empty)
*/
BinarySearchTree::BinaryNode * BinarySearchTree::findMax(BinarySearchTree::BinaryNode *t) const
{
// If our tree is empty
if (t == NULL)
return NULL;
// If current node has no larger children, it is max
if (t->right == NULL)
return t;
// Move down the right side of our tree and check again
return findMax(t->right);
}
/** contains
* @brief Determines if the value exists within the given BinaryNode and its children
*
* @param x The value to search for within the BST
* @param t The root BinaryNode to beign the search
* @return true If the value is found within the root node or any of its children
* @return false If the value is not found within the root node or any of its children
*/
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;
}
/** makeEmpty
* @brief Recursively delete the given root BinaryNode and all of its children
*
* @param t The root BinaryNode to delete, along with all child nodes
*/
void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & t)
{
if (t != NULL) {
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
t = NULL;
}
/** printInOrder
* @brief Output the element of the root nodes between printing their left and right subtrees
*
* @param t The root BinaryNode to begin the 'In Order' output
*/
void BinarySearchTree::printInOrder(BinaryNode *t) const
{
if(t != NULL) {
printInOrder(t->left);
std::cout << t->element << " ";
printInOrder(t->right);
}
}
/** printPostOrder
* @brief Output the value of the root nodes only after their subtrees
*
* @param t The root BinaryNode to begin the 'Post Order' output
*/
void BinarySearchTree::printPostOrder(BinaryNode *t) const
{
if (t != NULL) {
printPostOrder(t->left);
printPostOrder(t->right);
std::cout << t->element << " ";
}
}
/** printPreOrder
* @brief Output the value of the noot nodes before their subtrees
*
* @param t The root BinaryNode to begin the 'Pre Order' output
*/
void BinarySearchTree::printPreOrder(BinaryNode *t) const
{
if (t != NULL) {
std::cout << t->element << " ";
printPreOrder(t->left);
printPreOrder(t->right);
}
}

View File

@ -0,0 +1,56 @@
/*#############################################################################
## 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 ##
##############################################################################
## bst.h
*/
#ifndef BST_H
#define BST_H
#include <iostream>
// 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();
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;
};
#endif //BST_H

View File

@ -0,0 +1,91 @@
/*#############################################################################
## 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 ##
##############################################################################
## driver.cpp
*/
#include "bst.h"
#include <iostream>
enum OPS {
EXIT, INSERT, REMOVE, CONTAINS, INFIX, PREFIX, POSTFIX, EMPTY, MIN, MAX
};
int main()
{
std::cout << "Driver: \n";
BinarySearchTree testList;
bool exit = false;
int choice = -1;
int val;
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";
std::cin >> choice;
std::cin.clear();
switch (choice) {
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 REMOVE:
std::cout << "Enter a value to remove from our tree: ";
std::cin >> val;
std::cin.clear();
testList.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 INFIX:
testList.printInOrder();
break;
case PREFIX:
testList.printPreOrder();
break;
case POSTFIX:
testList.printPostOrder();
break;
case EMPTY:
testList.makeEmpty();
break;
case MIN:
std::cout << "Min value within our tree: " << testList.findMin();
break;
case MAX:
std::cout << "Max value within our tree: " << testList.findMax();
break;
default:
std::cout << "Invalid entry...\n";
break;
}
}
}