BLT/include/blt/std/binary_tree.h

227 lines
8.8 KiB
C
Raw Normal View History

2023-01-10 10:45:11 -05:00
/*
* Created by Brett on 09/01/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <stdexcept>
#include <vector>
#include <blt/std/queue.h>
#include <iostream>
2023-01-12 12:18:39 -05:00
#include <memory>
2023-01-10 10:45:11 -05:00
#ifndef BLT_BINARY_TREE_H
#define BLT_BINARY_TREE_H
namespace blt {
class binary_search_tree_error : public std::runtime_error {
public:
explicit binary_search_tree_error(const std::string& string): runtime_error(string) {}
};
template<typename T>
class node_binary_search_tree {
protected:
struct BST_node {
BST_node* left = nullptr;
BST_node* right = nullptr;
T payload;
2023-01-10 22:48:02 -05:00
explicit BST_node(const T& _payload) {
payload = _payload;
}
2023-01-10 10:45:11 -05:00
};
BST_node* m_root = nullptr;
private:
void insert(BST_node* root, const T& element) {
if (root == nullptr)
throw binary_search_tree_error{"Unable to insert. Provided root is null!\n"};
2023-01-10 10:45:11 -05:00
BST_node* searchNode = root;
// basically we are iterating through the tree looking for a valid node to insert into.
while (true) {
if (element == searchNode->payload)
throw binary_search_tree_error{"Unable to insert. Nodes cannot have equal values! (" + std::to_string(element) + ")\n"};
2023-01-10 10:45:11 -05:00
// check for left and right tree traversal if it exists
2023-01-10 22:58:49 -05:00
if (searchNode->left != nullptr && element < searchNode->payload) {
2023-01-10 10:45:11 -05:00
searchNode = searchNode->left;
continue;
}
2023-01-10 22:58:49 -05:00
if (searchNode->right != nullptr && element > searchNode->payload) {
2023-01-10 10:45:11 -05:00
searchNode = searchNode->right;
continue;
}
// insert into the lowest node consistent with a BST
2023-01-10 22:48:02 -05:00
if (element < searchNode->payload)
searchNode->left = new BST_node(element);
else
searchNode->right = new BST_node(element);
2023-01-10 10:45:11 -05:00
return;
}
}
2023-01-12 12:18:39 -05:00
2023-01-10 22:28:32 -05:00
BST_node* search(BST_node** parent, const T& element) const {
2023-01-10 10:45:11 -05:00
BST_node* searchNode = m_root;
BST_node* parentNode = m_root;
if (searchNode->left == nullptr && searchNode->right == nullptr)
return nullptr;
2023-01-10 10:45:11 -05:00
// basically we are iterating through the tree looking for a valid node to insert into.
while (searchNode->payload != element) {
if (searchNode == nullptr)
2023-01-10 22:30:54 -05:00
return nullptr;
2023-01-10 10:45:11 -05:00
// check for left and right tree traversal if it exists
if (element < searchNode->payload) {
parentNode = searchNode;
2023-01-10 10:45:11 -05:00
searchNode = searchNode->left;
} else {
parentNode = searchNode;
2023-01-10 10:45:11 -05:00
searchNode = searchNode->right;
}
}
if (parent != nullptr)
*parent = parentNode;
return searchNode;
2023-01-10 10:45:11 -05:00
}
std::vector<BST_node*> inOrderTraverse(BST_node* root) {
std::vector<BST_node*> nodes{};
blt::flat_stack<BST_node*> nodeStack{};
BST_node* current = root;
while (current != nullptr || !nodeStack.isEmpty()) {
// go all the way to the left subtree
2023-01-10 22:48:02 -05:00
while (current != nullptr) {
2023-01-10 10:45:11 -05:00
nodeStack.push(current);
current = current->left;
}
2023-01-10 22:05:47 -05:00
// take the parent node of the left most subtree
current = nodeStack.top();
2023-01-10 10:45:11 -05:00
nodeStack.pop();
nodes.push_back(current);
2023-01-10 22:05:47 -05:00
// traverse its right tree
2023-01-10 10:45:11 -05:00
current = current->right;
}
return nodes;
}
2023-01-12 12:18:39 -05:00
BST_node*& findMin(BST_node* root) {
BST_node*& searchNode = root;
while (searchNode->left != nullptr)
searchNode = searchNode->left;
return searchNode;
}
2023-01-12 12:18:39 -05:00
BST_node*& findMax(BST_node* root) {
BST_node*& searchNode = root;
while (searchNode->right != nullptr)
searchNode = searchNode->right;
return searchNode;
}
2023-01-12 12:18:39 -05:00
BST_node* remove(BST_node* root, const T& element) {
if (root->payload < element) // search left
2023-01-12 12:18:39 -05:00
root->left = remove(root->left, element);
else if (root->payload > element) // search right
2023-01-12 12:18:39 -05:00
root->right = remove(root->right, element);
else {
if (root->left != nullptr && root->right != nullptr) {
2023-01-12 12:18:39 -05:00
root->payload = findMin(root->right)->payload;
root->right = remove(root->right, root->payload);
}
}
2023-01-12 12:18:39 -05:00
return root;
}
2023-01-10 10:45:11 -05:00
public:
node_binary_search_tree() = default;
2023-01-10 22:48:02 -05:00
2023-01-10 22:21:23 -05:00
inline void insert(const T& element) {
if (m_root == nullptr) {
2023-01-10 22:48:02 -05:00
m_root = new BST_node(element);
return;
}
2023-01-10 10:45:11 -05:00
insert(m_root, element);
}
2023-01-10 22:21:23 -05:00
[[nodiscard]] inline BST_node* search(const T& element) const {
2023-01-10 22:28:32 -05:00
return search(nullptr, element);
2023-01-10 10:45:11 -05:00
}
2023-01-12 12:18:39 -05:00
void remove(const T& element) {
BST_node* parent = nullptr;
2023-01-10 22:28:32 -05:00
BST_node* elementNode = search(&parent, element);
if (parent == elementNode)
parent = nullptr;
2023-01-10 22:48:02 -05:00
if (elementNode->left != nullptr && elementNode->right != nullptr) {
auto traverseNodes = inOrderTraverse(elementNode);
if (parent == nullptr) {
m_root = nullptr;
} else {
2023-01-16 14:08:28 -05:00
// remove references to the nodes, we will add them later. We have a copy of the pointers which will be deleted.
if (parent->right == elementNode)
parent->right = nullptr;
else if (parent->left == elementNode)
parent->left = nullptr;
else
throw binary_search_tree_error("Parent node doesn't own child!\n");
}
2023-01-16 14:08:28 -05:00
// re-add all nodes to the tree, this is a terrible way of doing this, TODO.
for (auto* node : traverseNodes) {
if (node != elementNode) {
if (parent == nullptr) {
insert(node->payload);
} else
insert(parent, node->payload);
delete(node);
}
}
2023-01-10 22:05:47 -05:00
} else {
auto replacementNode = elementNode->left != nullptr ? elementNode->left : elementNode->right;
if (parent == nullptr)
m_root = replacementNode;
else {
if (parent->right == elementNode)
parent->right = replacementNode;
else if (parent->left == elementNode)
parent->left = replacementNode;
else
throw binary_search_tree_error("Parent node doesn't contain element of search!\n");
}
2023-01-10 10:45:11 -05:00
}
delete (elementNode);
2023-01-10 22:05:47 -05:00
}
2023-01-10 22:48:02 -05:00
inline std::vector<BST_node*> inOrderTraverse() {
2023-01-10 22:05:47 -05:00
return inOrderTraverse(m_root);
2023-01-10 10:45:11 -05:00
}
2023-01-10 22:48:02 -05:00
2023-01-16 14:08:28 -05:00
inline BST_node* findMin(){return findMin(m_root);}
inline BST_node* findMax(){return findMax(m_root);}
2023-01-10 10:45:11 -05:00
~node_binary_search_tree() {
2023-01-12 12:18:39 -05:00
auto inOrder = inOrderTraverse();
for (auto* n : inOrder)
delete(n);
2023-01-10 10:45:11 -05:00
}
};
template<typename T>
2023-01-16 14:08:28 -05:00
class heap {
2023-01-10 10:45:11 -05:00
private:
2023-01-16 14:08:28 -05:00
//TODO
2023-01-10 10:45:11 -05:00
};
template<typename T>
using node_BST = node_binary_search_tree<T>;
template<typename T>
2023-01-16 14:08:28 -05:00
using flat_binary_search_tree = heap<T>;
template<typename T>
2023-01-10 10:45:11 -05:00
using flat_BST = flat_binary_search_tree<T>;
}
#endif //BLT_BINARY_TREE_H