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:
parent
202953de49
commit
a8b6627135
|
@ -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)
|
||||||
|
|
|
@ -16,3 +16,4 @@ project (
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(binary)
|
add_subdirectory(binary)
|
||||||
|
add_subdirectory(redblack)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;}
|
||||||
|
|
Loading…
Reference in New Issue