Appreciate your thoughts and feedback...
BST.h
//
// BST.h
// BST
//
//
//
//
#ifndef BST_h
#define BST_h
// includes
#include <memory>
#include <string>
#include <iostream>
namespace bst {
template<class Key, class Data>
class BST
{
public:
//
// Node
//
class Node {
public:
Node(const Key& k, const Data& d, Node* p)
: key(k)
, data(d)
, left(nullptr)
, right(nullptr)
, parent(p) {}
Node(const Key& k, const Data& d, std::unique_ptr<Node>& l, std::unique_ptr<Node>& r, Node* p)
: key(k)
, data(d)
, left(std::move(l))
, right(std::move(r))
, parent(p) {}
const Key& GetKey() const { return key; }
Key& GetKey() { return key; }
const Data& GetData() const { return data; }
Data& GetData() { return data; }
std::unique_ptr<Node>& GetLeft() { return left; }
const std::unique_ptr<Node>& GetLeft() const { return left; }
std::unique_ptr<Node>& GetRight() { return right; }
const std::unique_ptr<Node>& GetRight() const { return right; }
Node* GetParent() { return parent; }
const Node* GetParent() const { return parent; }
void SetLeft(std::unique_ptr<Node>& l) { left = std::move(l); }
void SetRight(std::unique_ptr<Node>& r) { right = std::move(r); }
void SetParent(Node* p) { parent = p; }
void SetData(const Data& d) { data = d; }
private:
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
Node* parent;
Key key;
Data data;
};
//
// BST
//
BST()
: root(nullptr) {}
void Insert(const Key& k, const Data& d);
void Remove(const Key& k);
void Print(std::ostream& os);
private:
void InsertHelper(std::unique_ptr<Node>& node, const Key& k, const Data& d);
void RemoveHelper(std::unique_ptr<Node>& node, const Key& k);
void PrintHelper(std::ostream& os, std::unique_ptr<Node>& node);
private:
std::unique_ptr<Node> root;
}; // BST
} // bst
template<class Key, class Data>
void bst::BST<Key,Data>::Remove(const Key& k)
{
if(root) {
RemoveHelper(root, k);
} else {
// empty tree
}
}
template<class Key, class Data>
void bst::BST<Key,Data>::RemoveHelper(std::unique_ptr<Node>& node, const Key& k)
{
if(node->GetKey() == k) {
// found
if(node->GetRight() && node->GetLeft()) {
// 2 child
// swap with left child
// call function with new left child
// make a copy of left
std::unique_ptr<Node> leftLeft = std::move(node->GetLeft()->GetLeft());
std::unique_ptr<Node> leftRight = std::move(node->GetLeft()->GetRight());
// make a copy of node
std::unique_ptr<Node> left = std::move(node->GetLeft());
std::unique_ptr<Node> nodeRight = std::move(node->GetRight());
Node* nodeParent = node->GetParent();
bool isRightChild = false;
if(nodeParent && nodeParent->GetRight() == node) {
isRightChild = true;
}
// setup node
node->SetParent(left.get());
node->SetRight(leftRight);
node->SetLeft(leftLeft);
// setup left
left->SetParent(nodeParent);
left->SetLeft(node);
left->SetRight(nodeRight);
// connect left to parent
// and recursively call
if(isRightChild) {
if(nodeParent) {
nodeParent->SetRight(left);
RemoveHelper(nodeParent->GetRight(), k);
} else {
root = std::move(left);
RemoveHelper(root->GetLeft(), k);
}
} else {
if(nodeParent) {
nodeParent->SetLeft(left);
RemoveHelper(nodeParent->GetLeft()->GetLeft(), k);
} else {
root = std::move(left);
RemoveHelper(root->GetLeft(), k);
}
}
} else if(node->GetRight()) {
// 1 child
// make a copy of left
std::unique_ptr<Node> rightLeft = std::move(node->GetRight()->GetLeft());
std::unique_ptr<Node> rightRight = std::move(node->GetRight()->GetRight());
// make a copy of node
std::unique_ptr<Node> right = std::move(node->GetRight());
std::unique_ptr<Node> nodeLeft = std::move(node->GetLeft());
Node* nodeParent = node->GetParent();
bool isRightChild = false;
if(nodeParent && nodeParent->GetRight() == node) {
isRightChild = true;
}
// setup node
node->SetParent(right.get());
node->SetRight(rightRight);
node->SetLeft(rightLeft);
// setup left
right->SetParent(nodeParent);
right->SetRight(node);
right->SetLeft(nodeLeft);
// connect left to parent
// and recursively call
if(isRightChild) {
if(nodeParent) {
nodeParent->SetRight(right);
RemoveHelper(nodeParent->GetRight()->GetRight(), k);
} else {
root = std::move(right);
RemoveHelper(root->GetRight(), k);
}
} else {
if(nodeParent) {
nodeParent->SetLeft(right);
RemoveHelper(nodeParent->GetLeft()->GetRight(), k);
} else {
root = std::move(right);
RemoveHelper(root->GetRight(), k);
}
}
} else if(node->GetLeft()) {
// 1 child
// make a copy of left
std::unique_ptr<Node> leftLeft = std::move(node->GetLeft()->GetLeft());
std::unique_ptr<Node> leftRight = std::move(node->GetLeft()->GetRight());
// make a copy of node
std::unique_ptr<Node> left = std::move(node->GetLeft());
std::unique_ptr<Node> nodeRight = std::move(node->GetRight());
Node* nodeParent = node->GetParent();
bool isRightChild = false;
if(nodeParent && nodeParent->GetRight() == node) {
isRightChild = true;
}
// setup node
node->SetParent(left.get());
node->SetRight(leftRight);
node->SetLeft(leftLeft);
// setup left
left->SetParent(nodeParent);
left->SetLeft(node);
left->SetRight(nodeRight);
// connect left to parent
// and recursively call
if(isRightChild) {
if(nodeParent){
nodeParent->SetRight(left);
RemoveHelper(nodeParent->GetRight()->GetLeft(), k);
} else {
root = std::move(left);
RemoveHelper(root->GetLeft(), k);
}
} else {
if(nodeParent) {
nodeParent->SetLeft(left);
RemoveHelper(nodeParent->GetLeft()->GetLeft(), k);
} else {
root = std::move(left);
RemoveHelper(root->GetLeft(), k);
}
}
} else {
// leaf
// remove
node.reset();
}
} else if(node->GetRight() && node->GetRight()->GetKey() < k) {
RemoveHelper(node->GetRight(), k);
} else if(node->GetLeft() && node->GetLeft()->GetKey() > k) {
RemoveHelper(node->GetLeft(), k);
} else {
// not found
}
}
template<class Key, class Data>
void bst::BST<Key,Data>::Insert(const Key& k, const Data& d)
{
if(root) {
InsertHelper(root, k, d);
} else {
root = std::unique_ptr<Node>(new Node(k,d, nullptr));
}
}
template<class Key, class Data>
void bst::BST<Key,Data>::InsertHelper(std::unique_ptr<Node>& node, const Key& k, const Data& d)
{
if(node->GetKey() < k) {
// insert into right subtree
// first check there is a right subtree
if(node->GetRight()) {
// recursivley traverse the right subtree
InsertHelper(node->GetRight(), k, d);
} else {
// no right subtree?
// then insert item as right child
std::unique_ptr<Node> tempNode(new Node(k,d, node.get()));
node->SetRight(tempNode);
}
} else if(node->GetKey() > k) {
// insert into left subtree
// first check there is a left subtree
if(node->GetLeft()) {
// recursivley traverse the left subtree
InsertHelper(node->GetLeft(), k, d);
} else {
// no left subtree?
// then insert item as left child
std::unique_ptr<Node> tempNode(new Node(k,d, node.get()));
node->SetLeft(tempNode);
}
} else {
// found
// insert here
node->SetData(d);
}
}
template<class Key, class Data>
void bst::BST<Key,Data>::Print(std::ostream& os)
{
if(!root) {
PrintHelper(os, root);
}
}
template<class Key, class Data>
void bst::BST<Key,Data>::PrintHelper(std::ostream& os, std::unique_ptr<Node>& node)
{
// print key
os << "Key: " << node->GetKey() << std::endl;
if(node->GetLeft()) {
os << "Left: " << node->GetLeft()->GetKey() << std::endl;
} else {
os << "Left: null" << std::endl;
}
if(node->GetRight()) {
os << "Right: " << node->GetRight()->GetKey() << std::endl;
} else {
os << "Right: null" << std::endl;
}
os << std::endl;
if(node->GetLeft()) {
PrintHelper(os, node->GetLeft());
}
if(node->GetRight()) {
PrintHelper(os, node->GetRight());
}
}
#endif /* BST_h */
main.cpp
//
// main.cpp
// BST
//
//
//
//
#include <iostream>
#include "BST.h"
int main(int argc, const char * argv[]) {
bst::BST<int,int> bst1;
bst1.Insert(6, 6);
bst1.Insert(4, 4);
bst1.Insert(8, 8);
bst1.Insert(3, 3);
bst1.Insert(5, 5);
bst1.Insert(7, 7);
bst1.Insert(9, 9);
bst1.Print(std::cout);
bst1.Remove(6);
bst1.Print(std::cout);
// insert code here...
std::cout << "Hello, World!\n";
std::cin.get();
return 0;
}
I have added the code to github here
Am using a unique pointer to manager memory. Each node owns its left and right child. Can only move a child node.