I have made this BST using templates
Node.h
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
template<typename T>
class Node
{
public:
Node<T> *pLeft;
Node<T> *pRight;
T val;
Node<T>(T val)
{
this->val = val;
pLeft = pRight = nullptr;
}
// Node<T>(const Node<T>& src); -> to be implemented
// Node& operator=(const Node&); -> to be implemented
};
#endif // NODE_H_INCLUDED
Tree.h
#ifndef TREE_H_INCLUDED
#define TREE_H_INCLUDED
#include <iostream>
#include "Node.h"
template<typename T>
class Tree
{
Node<T>* root;
Node<T>* insert_at_sub(T i, Node<T>*);
Node<T>* delete_at_sub(T i, Node<T>*);
int countNodes(Node<T> *p);
void print_sub(Node<T> *p);
Node<T>* minValue(Node<T>*);
Node<T>* maxValue(Node<T>*);
Node<T>* get_last(Node<T>*);
Node<T>* get_first(Node<T>*);
int t_size = 0;
public:
Tree ()
{
root = nullptr;
}
~Tree()
{
delete root;
}
void add(T i)
{
++t_size;
root = insert_at_sub(i, root);
}
void print()
{
print_sub(root);
};
bool contain(T i)
{
return contain_sub(i, root);
}
bool contain_sub(T i, Node<T> *p);
void destroy(T i)
{
if(contain(i))
root = delete_at_sub(i, root);
else
return;
}
void showFirst();
void showLast();
int get_size()
{
return t_size;
}
int getNumberLeftNodes()
{
return countNodes(root->pLeft);
}
int getNumberRightNodes()
{
return countNodes(root->pRight);
}
};
template<typename T>
int Tree<T>::countNodes(Node<T> *p)
{
static int nodes;
if(!p)
return 0;
if (p->pLeft)
{
++nodes;
countNodes(p->pLeft);
}
if (p->pRight)
{
++nodes;
countNodes(p->pRight);
}
return nodes + 1;
}
template<typename T>
Node<T>* Tree<T>::insert_at_sub(T i, Node<T> *p)
{
if( ! p )
return new Node<T>(i);
else if (i <= p->val)
p->pLeft = insert_at_sub(i, p->pLeft);
else if (i > p->val)
p->pRight = insert_at_sub(i, p->pRight);
return p;
}
template<typename T>
void Tree<T>::print_sub(Node<T> *p)
{
if(p)
{
print_sub(p->pLeft);
std::cout << p->val << std::endl;
print_sub(p->pRight);
}
}
template<typename T>
bool Tree<T>::contain_sub(T i, Node<T> *p)
{
if (!p)
return false;
else if(i == p->val)
return true;
else if (i <= p->val)
contain_sub(i, p->pLeft);
else
contain_sub(i, p->pRight);
}
template<typename T>
Node<T> *Tree<T>::minValue(Node<T> *p)
{
Node<T> *current = p;
while(current && current->pLeft)
current = current->pLeft;
return current;
}
template<typename T>
Node<T> *Tree<T>::maxValue(Node<T> *p)
{
Node<T> *current = p;
while(current && current->pRight)
current = current->pRight;
return current;
}
template<typename T>
void Tree<T>::showLast()
{
Node<T> *last = maxValue(root);
if(last)
std::cout << last->val;
else
std::cout << "";
}
template<typename T>
void Tree<T>::showFirst()
{
Node<T> *first = minValue(root);
if(first)
std::cout << first->val;
else
std::cout << "";
}
template<typename T>
Node<T>* Tree<T>::delete_at_sub(T i, Node<T>* p)
{
if (i < p->val)
p->pLeft = delete_at_sub(i, p->pLeft);
else if (i > p->val)
p->pRight = delete_at_sub(i, p->pRight);
else if(i == p->val)
{
if ( ! p->pLeft)
{
Node<T> *temp = p->pRight;
delete p;
return temp;
}
else if ( ! p->pRight)
{
Node<T> *temp = p->pLeft;
delete p;
return temp;
}
Node<T> *temp = minValue(p->pRight);
p->val = temp->val;
p->pRight = delete_at_sub(p->val, p->pRight);
}
return p;
}
#endif // TREE_H_INCLUDED
main.cpp
#include <iostream>
#include "Tree.h"
using namespace std;
class Test
{
string name;
public:
Test () {}
Test(string name_) : name(name_) {}
friend ostream& operator<<(ostream& os, Test& t)
{
os << t.name;
return os;
}
bool operator<(Test t);
bool operator<=(Test t);
bool operator>(Test t);
};
bool Test::operator<(Test t)
{
return (name < t.name);
}
bool Test::operator<=(Test t)
{
return (name <= t.name);
}
bool Test::operator>(Test t)
{
return (name > t.name);
}
int main()
{
Tree<int> tr;
/*
4
/ \
1 6
/ \ / \
0 2 5 9
\
89
/ \
12 222
\
32
/
22
*/
tr.add(4);
tr.add(6);
tr.add(1);
tr.add(9);
tr.add(2);
tr.add(0);
tr.add(89);
tr.add(12);
tr.add(32);
tr.add(5);
tr.add(22);
tr.add(222);
// tr.test();
tr.showFirst();
cout << endl;
tr.showLast();
cout << endl;
Tree<string> bst;
bst.add("Zanildo");
bst.add("Helder");
bst.add("Wilson");
bst.add("Ady");
bst.add("Adilson");
bst.add("Patrick");
bst.showFirst();
cout << endl;
bst.showLast();
cout << endl;
Tree<Test> test;
test.add({"Jhonny"});
test.add({"Bruno"});
test.add({"Garry"});
test.add({"Henry"});
test.add({"Amber"});
test.add({"Brandy"});
test.add({"Danny"});
test.add({"Cameron"});
test.add({"Edla"});
test.add({"Zenalda"});
test.showFirst();
cout << endl;
test.showLast();
cout << endl;
//test.print();
return 0;
}
I put all the Tree
class functions implementation inside the header file because didn't want to put'em in a cpp file and having to add the explicit instantiation at the end of the file like this for example:
template class Tree<int>; // explicit instantiation
I also know I have to provide a copy constructor
and an assignment operator
for the Node
class but I am still studying how to implement them correctly as this is my first time having the need to provide either of them. I have studied them before but while googling around came across the copy-swap idiom
which is said to be the best approach so I have a few tabs open to study it and try to implement it. If anyone wish to give me a head start would be more than welcome.
An iterative BST is better for performance when the tree gets quite large but I have made the main functions for this BST recursively
on purpose. I know how to implement those functions iteratively
but not all of them yet.
After I want to create this BST entirely iterative
.
Besides all this, what can be said about my BST with template
?