Update example of red-black and binary tree algorithms

+ Use copy-swap idiom for assignment operators
+ Update and organize CMakeLists subdirectories for algorithm examples
This commit is contained in:
Shaun Reed 2021-06-09 10:16:24 -04:00
parent 202953de49
commit a8b6627135
6 changed files with 51 additions and 60 deletions

View File

@ -15,12 +15,12 @@ project (
LANGUAGES CXX LANGUAGES CXX
) )
add_subdirectory(merge)
add_subdirectory(selection)
add_subdirectory(insertion)
add_subdirectory(bubble) add_subdirectory(bubble)
add_subdirectory(heap)
add_subdirectory(quick)
add_subdirectory(count)
add_subdirectory(bucket) add_subdirectory(bucket)
add_subdirectory(count)
add_subdirectory(heap)
add_subdirectory(insertion)
add_subdirectory(merge)
add_subdirectory(quick)
add_subdirectory(radix) add_subdirectory(radix)
add_subdirectory(selection)

View File

@ -16,3 +16,4 @@ project (
) )
add_subdirectory(binary) add_subdirectory(binary)
add_subdirectory(redblack)

View File

@ -17,51 +17,48 @@
*******************************************************************************/ *******************************************************************************/
/** BinarySearchTree Copy Assignment Operator /** BinarySearchTree Copy Assignment Operator
* @brief Empty the calling object's root BinaryNode, and copy the rhs data * @brief Empty the calling object's root BinaryNode, and swap the rhs data
* + Utilizes the copy-swap-idiom
* *
* Runs in O( n ) time, since we visit each node in the BST once * Runs in O( n ) time, since we call makeEmpty() which runs is O( n )
* + Where n is the total number of nodes within the BST
*
* makeEmpty() and clone() are both O( n ), and we call each sequentially
* + This would appear to be O( 2n ), but we drop the constant of 2
* *
* @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 BinarySearchTree The copied BinarySearchTree object
*/ */
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(root); makeEmpty(root);
// Copy rhs to this->root // Copy rhs to this->root
root = clone(rhs.root); std::swap(root, rhs.root);
return *this; return *this;
} }
/* BinaryNode Copy Constructor /* BinaryNode Copy Constructor
* @brief Recursively copy rhs node and all child nodes
* *
* Runs in O( n ) time, since we visit each node in the BST once * Runs in O( n ) time, since we visit each node in the BST once
* + Where n is the total number of nodes within the BST * + Where n is the total number of nodes within the BST
* *
* @param rhs An existing BST to initialize this node (and children) with * @param rhs An existing BST to initialize this node (and children) with
*/ */
BinarySearchTree::BinaryNode::BinaryNode(BinaryNode * toCopy) BinarySearchTree::BinaryNode::BinaryNode(const BinaryNode &rhs)
{ {
// Base case, breaks recursion when we hit a null node // Base case, breaks recursion when we hit a null node
// + Returns to the previous call in the stack // + Returns to the previous call in the stack
if (toCopy == nullptr) return; if (isEmpty(this)) return;
// Set the element of this BinaryNode to the value in toCopy->element // Set the element of this BinaryNode to the value in toCopy->element
element = toCopy->element; element = rhs.element;
// If there is a left / right node, copy it using recursion // If there is a left / right node, copy it using recursion
// + If there is no left / right node, set them to nullptr // + If there is no left / right node, set them to nullptr
if (toCopy->left != nullptr) { if (rhs.left != nullptr) {
left = new BinaryNode(toCopy->left); left = new BinaryNode(*rhs.left);
left->parent = this; left->parent = this;
} }
if (toCopy->right != nullptr) { if (rhs.right != nullptr) {
right = new BinaryNode(toCopy->right); right = new BinaryNode(*rhs.right);
right->parent = this; right->parent = this;
} }
} }
@ -113,19 +110,6 @@ void BinarySearchTree::makeEmpty(BinarySearchTree::BinaryNode * & tree)
} }
} }
/** isEmpty
* @brief Determine whether or not the calling BST object is empty
*
* Runs in constant time, O( 1 )
*
* @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 == nullptr;
}
/** insert /** insert
* @brief Insert a value into the tree starting at a given BinaryNode * @brief Insert a value into the tree starting at a given BinaryNode
* + Uses recursion * + Uses recursion
@ -268,6 +252,7 @@ BinarySearchTree::BinaryNode *BinarySearchTree::search(
if (start == nullptr || start->element == value) return start; if (start == nullptr || start->element == value) return start;
else if (start->element < value) return search(value, start->right); else if (start->element < value) return search(value, start->right);
else if (start->element > value) return search(value, start->left); else if (start->element > value) return search(value, start->left);
else return nullptr;
} }
/** findMin /** findMin
@ -382,7 +367,7 @@ BinarySearchTree::BinaryNode * BinarySearchTree::clone(BinaryNode *start)
if (start == nullptr) return nullptr; if (start == nullptr) return nullptr;
// Construct all child nodes through recursion, return root node // Construct all child nodes through recursion, return root node
return new BinaryNode(start); return new BinaryNode(*start);
} }
/** transplant /** transplant

View File

@ -27,12 +27,13 @@ public:
BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt, BinaryNode *p) BinaryNode(const int &el, BinaryNode *lt, BinaryNode *rt, BinaryNode *p)
:element(el), left(lt), right(rt), parent(p) {}; :element(el), left(lt), right(rt), parent(p) {};
// Ctor for a node and any downstream nodes // Ctor for a node and any downstream nodes
explicit BinaryNode(BinaryNode * toCopy); BinaryNode(const BinaryNode &rhs);
}; };
BinarySearchTree() : root(nullptr) {}; BinarySearchTree() : root(nullptr) {};
BinarySearchTree(const BinarySearchTree &rhs) : root(rhs.clone(rhs.root)) {}; BinarySearchTree(const BinarySearchTree &rhs) :
BinarySearchTree& operator=(const BinarySearchTree& rhs); root(BinarySearchTree::clone(rhs.root)) {};
BinarySearchTree& operator=(BinarySearchTree rhs);
~BinarySearchTree() { makeEmpty(root);}; ~BinarySearchTree() { makeEmpty(root);};
inline BinaryNode * getRoot() const { return root;} inline BinaryNode * getRoot() const { return root;}
@ -44,7 +45,8 @@ public:
inline void makeEmpty() { makeEmpty(root);} inline void makeEmpty() { makeEmpty(root);}
void makeEmpty(BinaryNode *&tree); void makeEmpty(BinaryNode *&tree);
// Checks if this BST is empty // Checks if this BST is empty
bool isEmpty() const; inline bool isEmpty() const { return isEmpty(root);}
static inline bool isEmpty(const BinaryNode *rhs) { return rhs == nullptr;}
// Insert and remove values from a tree or subtree // Insert and remove values from a tree or subtree
inline void insert(const int &x) { insert(x, root, nullptr);} inline void insert(const int &x) { insert(x, root, nullptr);}
@ -70,7 +72,11 @@ public:
BinaryNode * findMin(BinaryNode *start) const; BinaryNode * findMin(BinaryNode *start) const;
BinaryNode * findMax(BinaryNode *start) const; BinaryNode * findMax(BinaryNode *start) const;
inline BinaryNode * predecessor(const int &value) const
{ return predecessor(search(value));}
BinaryNode * predecessor(BinaryNode *startNode) const; BinaryNode * predecessor(BinaryNode *startNode) const;
inline BinaryNode * successor(const int &value) const
{ return successor(search(value));}
BinaryNode * successor(BinaryNode *startNode) const; BinaryNode * successor(BinaryNode *startNode) const;
private: private:

View File

@ -27,35 +27,35 @@ RedBlackTree::RedBlackNode *RedBlackTree::nil = new RedBlackTree::RedBlackNode()
* *
* @param rhs An existing RBT to initialize this node (and children) with * @param rhs An existing RBT to initialize this node (and children) with
*/ */
RedBlackTree::RedBlackNode::RedBlackNode(RedBlackNode * toCopy) RedBlackTree::RedBlackNode::RedBlackNode(const RedBlackNode &toCopy)
{ {
// Base case, breaks recursion when we hit a null node // Base case, breaks recursion when we hit a null node
// + Returns to the previous call in the stack // + Returns to the previous call in the stack
if (toCopy == nil) return; if (&toCopy == nil) return;
// Set the element of this RedBlackNode to the value in toCopy->element // Set the element of this RedBlackNode to the value in toCopy->element
element = toCopy->element; element = toCopy.element;
// If there is a left / right node, copy it using recursion // If there is a left / right node, copy it using recursion
// + If there is no left / right node, set them to nullptr // + If there is no left / right node, set them to nullptr
if (toCopy->left != nil) { if (toCopy.left != nil) {
left = new RedBlackNode(toCopy->left); left = new RedBlackNode(*toCopy.left);
left->parent = this; left->parent = this;
} }
else left = nil; else left = nil;
if (toCopy->right != nil) { if (toCopy.right != nil) {
right = new RedBlackNode(toCopy->right); right = new RedBlackNode(*toCopy.right);
right->parent = this; right->parent = this;
} }
else right = nil; else right = nil;
if (toCopy->parent == nil) parent = nil; if (toCopy.parent == nil) parent = nil;
// TODO: Fix the copying of the RBT color = toCopy.color;
color = toCopy->color;
} }
/** RedBlackTree Copy Assignment Operator /** RedBlackTree Copy Assignment Operator
* @brief Empty the calling object's root RedBlackNode, and copy the rhs data * @brief Empty the calling object's root RedBlackNode, swap with the rhs data
* + Utilizes the copy-swap-idiom
* *
* Runs in O( n ) time, since we visit each node in the RBT once * Runs in O( n ) time, since we visit each node in the RBT once
* + Where n is the total number of nodes within the RBT * + Where n is the total number of nodes within the RBT
@ -66,17 +66,15 @@ RedBlackTree::RedBlackNode::RedBlackNode(RedBlackNode * toCopy)
* @param rhs The RBT to copy, beginning from its root RedBlackNode * @param rhs The RBT to copy, beginning from its root RedBlackNode
* @return RedBlackTree The copied RedBlackTree object * @return RedBlackTree The copied RedBlackTree object
*/ */
RedBlackTree& RedBlackTree::operator=(const RedBlackTree &rhs) RedBlackTree& RedBlackTree::operator=(RedBlackTree 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(root); makeEmpty(root);
// if (root == nil) root = new RedBlackNode();
// Copy rhs to this->root // Copy rhs to this->root
root = clone(rhs.root); std::swap(root, rhs.root);
return *this; return *this;
} }
@ -119,7 +117,7 @@ bool RedBlackTree::contains(const int &value, RedBlackNode *start) const
*/ */
void RedBlackTree::rotateLeft(RedBlackNode *pivotNode) void RedBlackTree::rotateLeft(RedBlackNode *pivotNode)
{ {
// To rotateRight, we must relocate the rightChild node // To rotateLeft, we must relocate the rightChild node
RedBlackNode *rightChild = pivotNode->right; RedBlackNode *rightChild = pivotNode->right;
pivotNode->right = rightChild->left; pivotNode->right = rightChild->left;
@ -640,6 +638,7 @@ RedBlackTree::RedBlackNode *RedBlackTree::search(
if (start == nil || start->element == value) return start; if (start == nil || start->element == value) return start;
else if (start->element < value) return search(value, start->right); else if (start->element < value) return search(value, start->right);
else if (start->element > value) return search(value, start->left); else if (start->element > value) return search(value, start->left);
else return nullptr;
} }
/** findMin /** findMin
@ -756,7 +755,7 @@ RedBlackTree::RedBlackNode * RedBlackTree::clone(RedBlackNode *start)
if (start == nil) return nil; if (start == nil) return nil;
// Construct all child nodes through recursion, return root node // Construct all child nodes through recursion, return root node
return new RedBlackNode(start); return new RedBlackNode(*start);
} }
/** transplant /** transplant

View File

@ -30,13 +30,13 @@ public:
RedBlackNode *lt, RedBlackNode *rt, RedBlackNode *p) RedBlackNode *lt, RedBlackNode *rt, RedBlackNode *p)
:element(el), color(c), left(lt), right(rt), parent(p) {}; :element(el), color(c), left(lt), right(rt), parent(p) {};
// Ctor for copying a node and any downstream nodes // Ctor for copying a node and any downstream nodes
explicit RedBlackNode(RedBlackNode * toCopy); RedBlackNode(const RedBlackNode &toCopy);
}; };
static RedBlackNode *nil; static RedBlackNode *nil;
RedBlackTree() : root(nil) {}; RedBlackTree() : root(nil) {};
RedBlackTree(const RedBlackTree &rhs);; RedBlackTree(const RedBlackTree &rhs);;
RedBlackTree& operator=(const RedBlackTree& rhs); RedBlackTree& operator=(RedBlackTree rhs);
~RedBlackTree() { makeEmpty(root);}; ~RedBlackTree() { makeEmpty(root);};
// Inlined functions provide less verbose interface for using the RBT // Inlined functions provide less verbose interface for using the RBT
inline RedBlackNode * getRoot() const { return root;} inline RedBlackNode * getRoot() const { return root;}