I have recently been implementing a binary tree in my free-time and I do believe I have it working correctly. However, I have ran into a mysterious segmentation fault when running a simple test. Here is my implementation of the binary search tree:
//the binary search tree class
template <class M>
class BS_Tree {
private:
//node structure
struct Node {
M data; //the key of the node
Node* left,* right,* parent; //node pointers to left right and parent
Node(M key, Node* p) //parameterized node constructor
: data(key), left(nullptr), right(nullptr), parent(p) {}
};
Node* root; //the root node of the binary search tree
bool is_left(Node* n) {return n->parent->left == n;} //utility function
void destroy(Node* n); //used for tree destruction
void duplicate(Node* const &, Node* &); //used for copy construction
public:
BS_Tree() {root = nullptr;} //constructor
~BS_Tree() {destroy(root);} //destructor
BS_Tree(const BS_Tree &); //copy constructor
BS_Tree &operator=(const BS_Tree &); //copy assignment operator
Node* find(M key); //find function
void insert(M); //insert function
void erase(Node*); //erase function
Node* get_root() {return root;}
};
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if(n) { //recursively erase the tree
if(n->left) destroy(n->left);
if(n->right) destroy(n->right);
delete n;
}
}
//duplicate function used for copy construction
template <class M>
void BS_Tree<M>::duplicate(Node* const &one, Node* &two) {
if(!one) two = nullptr;
else { //recursively duplicate the tree
two = new Node(one->data);
duplicate(one->left, two->left);
duplicate(one->right, two->right);
}
}
//copy constructor
template <class M>
BS_Tree<M>::BS_Tree(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else duplicate(b.root, this->root); //call duplicate function
}
//copy assignment operator
template <class M>
BS_Tree<M> &BS_Tree<M>::operator=(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else { //destroy current tree and duplicate source tree
this->~BS_Tree();
duplicate(b.root, this->root);
}
}
//function to find a key and return a pointer
template <class M>
typename BS_Tree<M>::Node* BS_Tree<M>::find(M key) {
Node* i = root; //create an index
while(i) {
//try to find the key
if (i->data == key) return i;
if(i->data > key) i = i->left;
else i = i->right;
}
//return a pointer to the key, nullptr if not found
return i;
}
//function to insert a new node
template <class M>
void BS_Tree<M>::insert(M key) {
if(!root) { //if no tree, make new node the root
root = new Node(key, nullptr);
return;
}
Node* i = root; //create an index
while(true) { //find insertion point and insert new node
if(i->data > key) {
if(!i->left) {
i->left = new Node(key, i);
return;
}
else i = i->left;
}
if(i->data <= key) {
if(!i->right) {
i->right = new Node(key, i);
return;
}
else i = i->right;
}
}
}
//Function to erase a node
template <class M>
void BS_Tree<M>::erase(Node* n) {
if(n) {
//no children case
if(!n->left && !n->right) {
if(root == n) root = nullptr; //if node is root, make root null
else { //if node is a child, update parent's children
if(is_left(n)) n->parent->left = nullptr;
else n->parent->right = nullptr;
}
delete n; //erase the node
return;
}
//one child cases
if(!n->left) {
if(n == root){ //if node is root, update root
root = n->right;
n->right->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->right;
else n->parent->right = n->right;
n->right->parent = n->parent;
}
delete n; //erase the node
return;
}
if(!n->right) {
if(n == root){ //if node is root, update root
root = n->left;
n->left->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->left;
else n->parent->right = n->left;
n->left->parent = n->parent;
}
delete n; //erase the node
return;
}
//two children case
else {
Node* i = n; //create an index
i = i->right; //find successor
while(i->left) i = i->left;
n->data = i->data; //set nodes data to successor's data
if(is_left(i)) i->parent->left = i->right; //update successor's parent and its child
else i->parent->right = i->right;
if(i->right) i->right->parent = i->parent;
delete i; //erase successor node
return;
}
}
}
As for the test, it is a simple linear vector element insert vs time performance check. It takes a max number of elements and an increment of elements for each test. It then runs the test for each increment and times the insertions. It works fine for the first few iterations (i.e n = 10000, 20000, 30000, 40000), but then I reach a segmentation fault after insertion when the 50000 element tree destructor is called. It is hinting at the line:
if(n->right) destroy(n->right);
I understand that I am doing an incremental insertion so all of my elements are on the right side of the tree, but I am having a hard time figuring out where I went wrong and why it only messes up on this iteration.
My test implematation:
int main(){
//number of elements, max test elements, and test increment
int n, t = 100000, i = 10000;
//run the test a number of times
for(n = i; n <= t; n += i) {
//get an incremental vector of size n
std::vector<int> test(n);
std::iota(std::begin(test), std::end(test), 0);
//run the insert test print the time interval
BS_Tree<int> m;
auto ibs_start = clock();
for(auto i : test){
m.insert(i);
}
auto ibs_stop = clock();
std::cout << n << ' ' << (ibs_stop - ibs_start)/double(CLOCKS_PER_SEC)*1000 << "\n";
}
return 0;
}
If someone could help I would greatly appreciate it!
Edit: Could it simply be my stack overflowing due to the destroy function having to store all of the elements before reaching the bottom and actually deleting anything?
If it works for some number of items (40000), but not for a larger, it might be a stackoverflow. Looking at the code also confirms this: destroying is recursive, and in the case of extremely unbalanced tree, it means as many stack frames as many nodes.
The question is how this could be solved without recursion? This is not so obvious, as there are two recursive calls. My solution is to traverse the binary tree, post-order, and delete leaf nodes.
Here is a solution -- an iterative version of the destroy method:
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if (n) { // iteratively erase the tree
Node* c = n; // current node
while (true) {
if (c->right) {
// it has right child, descend to it
c = c->right;
continue;
}
if (c->left) {
// it has left child, descend to it
c = c->left;
continue;
}
// this node has no (more) children, destroy it
Node* p = c->parent;
if (p) {
// update its parent to no longer point to it
if (p->right == c) p->right = NULL; // we came from left
else if (p->left == c) p->left = NULL; // we came from left
}
// destroy the node
delete c;
// go back to its parent
c = p;
if (c == n) {
// where at back at start node, stop
delete n;
break;
}
}
}
}
Update: I have tested my solution, and made some small changes.
Related
I have a templated class with an additional Node class with a height attribute. I want to be able to validate the height of each node after a new node has been inserted. My insert node function is working well, I am just confused on how I would change the height of each node after a new node is inserted.
template <typename T>
class BST
{
public:
class Node
{
public:
T key;
int height = 0;
Node* left = nullptr;
Node* right = nullptr;
Node* parent = nullptr;
Node(){}
Node(T k, Node* input_node = nullptr)
{
key = k;
parent = input_node;
}
};
private:
Node* root_ = nullptr;
unsigned int size_ = 0;
public:
BST();
~BST();
void insert(T k);
private:
void fix_height(Node* node);
template <typename T>
void BST<T>::insert(T k)
{
Node* node = root_; // insert function
Node* prev_node = node;
bool went_right;
if(node == nullptr)
{
root_ = new Node(k);
++size_;
return;
}
while(node != nullptr)
{
prev_node = node;
if(k < node->key)
{
node = node->left;
went_right = false;
}
else if (k > node->key)
{
node = node->right;
went_right = true;
}
else
{
return;
}
}
if(went_right)
{
prev_node->right= new Node(k, prev_node); // assigning the new node
}
else
{
prev_node->left= new Node(k, prev_node);
}
++size_;
}
template <typename T>
void BST<T>::fix_height(Node* node)
{
}```
The height of a node is defined as the maximum of its child nodes' heights plus 1.
Although your question title speaks of "post-order" (a term related to recursion), your code is not actually recursive. Normally, a post-order update happens after a recursive call.
Anyway, with your iterative solution the height can still be updated easily because you have stored parent pointers in your tree nodes. And so all you need to do is walk back through each node and update the height.
template <typename T>
void BST<T>::fix_height(Node* node)
{
while (node)
{
node->height = 1 + std::max(
node->left ? node->left->height : -1,
node->right ? node->right->height : -1);
node = node->parent;
}
}
It should be noted that your tree heights appear to treat a leaf node's height (that is, the height of a node that has no children) as 0. In order to make your fix_height function well-behaved even if called on a leaf node, then the height of "no child" is treated as -1.
If you decide that a leaf node's height should actually be 1, then you should change those "no child" heights to 0, and change the default height of a new node to 1.
To use this, you would call fix_height(prev_node); just before returning from your insert function.
I have been trying to get this function working for the longest time now. It is part of an assignment for an online course, but it seems no matter what I submit, the function fails for both the empty child test and the left child test. See code below. The main() function is deliberately commented out. Any info./input is much appreciated.
// C++ binary trees and stuff;
//
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
class BST
{
public:
int data;
BST *left;
BST *right;
//BST *root;
// BST() constructor
BST (int num)
{
data = num;
left = nullptr;
right = nullptr;
root = nullptr;
}
// constructors for root node(s), initializing as root when no values exist yet;
BST() : root (nullptr){}
BST (BST *rootNode) : root(rootNode){}
void insert (int value)
{
BST *newNode = new BST();
newNode = root;
if (root == nullptr)
{
root = new BST (value);
}
else
{
root->data = value;
}
// check if newNode's value equals the passed-in value:
if (value == root->data)
{
//cout << "\nWarning! Value already exists in tree, so nothing will be done.\n";
return;
}
// check if value is < or > newNode's value:
if (value <= root->data)
{
if (root->left == nullptr)
{
// make a new node as the left child of this node,
root->left = new BST(value);
}
else
{
// recursively call insert() on tree's left side,
root->left->insert(value);
}
}
else
{
if (root->right == nullptr)
{
// make a new node as the right child of this node,
root->right = new BST(value);
}
else
{
// recursively call insert() on tree's right side,
root->right->insert(value);
}
}
}
public:
BST *root;
};
/*
int main (int argc, char *argv[])
{
//...insert code here,
// create nodes,...
BST rootNode(5);
BST leftNode(4);
BST rightNode(6);
// connect the nodes to the tree via rootNode.left and rootNode.right,..
rootNode.left = &leftNode;
rootNode.right = &rightNode;
printf ("\nData (root) value = %i, rootNode.left = %i, and rootNode.right = %i\n",
rootNode.data, rootNode.left->data, rootNode.right->data);
cout << "\n\nHello, Solar System!\n";
return 0;
}
*/
Okay, here's my suggestion. You need to reformat your code. You need two classes. You need a BST, and you need a Node. The various methods to add/remove/traverse are part of the BST class. Nodes are just Nodes.
So:
class BST_Node {
public:
int value;
BST_Node * left = nullptr;
BST_Node * right = nullptr;
// Define constructors, etc.
};
class BST {
public:
BST_Node * root = nullptr;
BST_Node * insert(int value);
void insertNode(BST_Node *node);
void insertNodeBelow(BST_Node *nodeToInsert, BST_Node *startingNode);
};
BST_Node * BST::insert(int value) {
BST_Node * node = new BST_Node(value);
insertNode(node);
return node;
}
void BST::insertNode(BST_Node *node) {
if (node == nullptr) {
return;
}
if (root == nullptr) {
root = node;
}
else {
insertNodeBelow(node, root);
}
}
void BST::insertNodeBelow(BST_Node *node, BST_Node *startingNode) {
if (node == nullptr || startingNode == nullptr) {
return;
}
if (node->value < startingNode->value) {
if (startingNode->left != nullptr) {
insertNodeBelow(node, startingNode->left);
}
else {
startingNode->left = node;
}
}
else {
if (startingNode->right != nullptr) {
insertNodeBelow(node, startingNode->right);
}
else {
startingNode->right = node;
}
}
}
How this works... First, the logic of how to store nodes is in BST. Nodes don't care. Second, I made methods for either inserting a value or a node. Because I think that's handy. That should be fairly easy to understand.
The root node can be null, if so, then your inserted node is now root. Otherwise it calls the recursive insertion function. Now, you could simplify this a little, but I didn't want to get too clever.
So it's simple. We look to see where it belongs relative to the point we're at (initially the root). Either we go into the left branch or the right branch. But that branch could be empty, so you just plop it right in. If it's not empty, then you recurse.
I didn't test it.
After randomly filling a linked list with a deck of 52 cards. When I try to print it, it will print the head node 52 times. Is there something wrong with my 'traverse through linked list logic' or something wrong with my insertion logic?
These are the Node helper methods (a bagNode has a CardOfBag and a next)
card *bagNode::getCard() // retreives card in the bagnode as pointer
{
return this->cardOfBag;
}
bagNode *bagNode::getNext() // retreives the next bagnode as pointer
{
return this->next;
}
void bagNode::setCard(card *card) // sets card of bagnode
{
this->cardOfBag = card;
}
void bagNode::setNext(bagNode *setNode) // sets next bagnode
{
setNode->next = this->next;
this->next = setNode;
}
These are the methods for the linked list (called bag):
it has a header, tail, and current bagNode* pointers.
void bag::add(bagNode *node) // adds node to random position
{
int i, place, size;
place = randomPosition();
size = getCurrentSize();
if (size == 0) // for initial insertion into empty linked list
{
setHead(node);
setTail(node);
alterSize(1);
} else {
if ((size - 1) == place) // if the insertion is at the last node
{
this->tail->setNext(node);
setTail(node);
alterSize(1);
} else {
if (place == 0) // if insertion is at head node
{
node->setNext(this->head);
setHead(node);
alterSize(1);
} else {
setCurrent(place); // for any insertion in between first and last nodes
node->setNext(current->getNext());
current->setNext(node);
alterSize(1);
}
}
}
}
int bag::getCurrentSize() // returns size of bag (linked list)
{
return this->size;
}
void bag::alterSize(int num) // changes the size int of bag by num
{
this->size = this->size + num;
}
int bag::randomPosition() // generates random number from 0 to size exclusive
{
int size = getCurrentSize();
if (size != 0)
return (rand() % size);
}
void bag::setCurrent(int desiredPosition) // this traverses the current pointer
// by desiredPosition steps from the head node
{
int i;
this->current = this->head;
for (i = 0; i < desiredPosition; i++) {
this->current->setNext(this->current->getNext());
}
}
bagNode *bag::getCurrentNode() // returns node of current pointer
{
return this->current;
}
bagNode::setNext() is supposed to make next point to the node provided; leave the other node alone:
void bagNode::setNext(bagNode* setNode) //sets next bagnode
{
this->next = setNode;
}
Your bag::setCurrent() doesn't work. You're supposed to make this->current keep going "next" until you hit the desiredPosition, instead you're only changing its next pointer to... the same value it previously had.
Do something like this instead:
void bag::setCurrent(int desiredPosition)
{
int i;
this->current = this->head;
for(i = 0; i < desiredPosition; i++)
{
this->current = this->current->getNext();
}
}
That should work better now.
in your function
void bag::setCurrent(int desiredPosition)
You are not changing this->current at all. Basically you did nothing in that function.
So, i'm attempting to create a LinkedList using dummy nodes, however, when running through the functionality of each function, I get errors when it comes to the overloaded brackets operator, which is suppose to returns the item at the given index: list[n] Though i'm not exactly sure what may be wrong with the code.
I've spent hours looking at why i'm getting errors when trying to run each function. Sorry the question is so vague, but I feel as though I'm missing something, or something is coded poorly that I can't seem to detect.
Here's the code.
#ifndef _LINKED_LIST_GUARD
#define _LINKED_LIST_GUARD 1
#include <iostream>
#include <string>
#include "ListInterface.h"
template <typename T>
class LinkedList : public ListInterface<T>
{
private:
// Created in order to keep track of list size
int count = 0;
public:
// Default contructor
LinkedList()
{
_head = new Node;
_tail = new Node;
_head->_next = _tail;
}
private:
//
// Private node class to facilitate linked list
//
class Node
{
public:
T _data;
Node* _next;
// Constructor: default
Node(T d = T{}, Node* n = nullptr) : _data(d), _next(n) {}
~Node() { _next = nullptr; }
};
//
// Prevent copying and assigning
//
LinkedList(const LinkedList& rhs) {}
const LinkedList& operator=(const LinkedList& rhs) {}
public:
//
// LinkedList instance variables; we use dummy head and tail nodes in this implementation
unsigned _size;
Node* _head;
Node* _tail;
// Returns the value that the head points to, sinze _head is a dummy node.
T& first() const
{
return _head->_next->_data;
}
// Adds an item to the LEFT side of the linked list
void push(const T& x)
{
// Creates a new node with the user input data.
Node* current = new Node;
current->_data = x;
//Sets the node next to this node to be equal to what the head was previously pointing to.
current->_next = _head->_next;
//Finally, sets the user created node to be the first node within the list, then adds to the count.
_head->_next = current;
count++;
}
T& operator[](unsigned n)
{
//Starts at position one, since this would never return zero.
int position = 1;
//If the user input value is greater than the amount of items in the list
if (n > count)
{
//Throws a string exception.
throw std::string("Invalid Positon");
}
//Loops through the LinkedList
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
//If the node at the current position is equal to the user input value
if (position == n)
{
//returns the current positions data, since it would be the data at user input position
return current->_data;
}
// If not, adds to position, and checks again.
position++;
}
return _head->_data;
}
//uses the pop function over and over until the list is empty, leaving only the _head and _tail dummy nodes.
void clear()
{
do
{
pop();
} while (count != 0);
}
bool contains(const T& target) const
{
//Loops through the LinkedList.
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
//While looping, if the current node's data is equal to the user input target data, returns true.
if (current->_data == target)
return true;
}
// If it never finds anything, returns false.
return false;
}
bool pop()
{
//The head would only point to the tail if the list were empty.
if (_head->_next == _tail)
{
std::cout << "Unable to pop, list is empty ";
return false;
}
if (_head->_next != _tail)
{
//Creates a new node that has its values equal to the first node within the list.
Node* deleteNode = _head->_next;
//Sets the front of the node to be equal to the first node after the heads next node.
_head->_next = _head->_next->_next;
//Finally, deletes the node that deleteNode points to, and reduces the count
delete deleteNode;
count--;
return true;
}
//If the pop is unsucessful, returns false.
return false;
}
T& last() const
{
// There can't be a last value if the list is empty, so throws an exception
if (_head->_next == _tail)
{
//throw std::string("List is empty.");
std::cout << "List is empty";
}
if (_head->_next != _tail)
{
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
//Loops through the list until the node that points to tail is located, then returns it.
if (current->_next == _tail)
return current->_data;
}
}
return _tail->_data;
}
int search(const T& target = T{}) const
{
//Once again, starts a position 1, since 0 is not a valid position
int position = 1;
//Loops through list
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
//While looping, if the current node's data is equal to the user input target, returns the position
if (current->_data == target)
{
return position;
}
//Otherwise increases the position, and loops again.
position++;
}
// If it is unable to find the target in the list, returns -1.
return -1;
}
bool isEmpty() const
{
// If the _head points to the tail, that means there are no nodes in between, meaning it is empty.
if (_head->_next == _tail)
{
return true;
}
//Otherwise, return false.
return false;
}
unsigned size() const
{
//Returns the count, which is altered by remove, pop, and push.
return count;
}
bool remove(const T& target)
{
//Creates a node, whose data is initially null.
Node* deleteNode = nullptr;
//Creates another node to follow behind it.
Node* trailer = _head;
//Finally, creates a node that is to represent the current node that is being pointed at.
Node* current = _head->_next;
//Loops
while (current != _tail && current->_data != target)
{
trailer = current;
current = current->_next;
}
//If the data is current is equal to the target
if (current->_data == target)
{
// Sets the node to be deleted to current
deleteNode = current;
//then, sets current to the node right after.
current = current->_next;
//Finally, sets the trailer to the current node, since it's no longer needed
trailer->_next = current;
//Then, simply delets the node, and subtracts from the count.
delete deleteNode;
count--;
return true;
}
else
// If it is unable to find the targeted value, returns false.
std::cout << "unable to remove, item not in list" << std::endl;
return false;
}
//
// Internal consistency check
//
public:
virtual bool check() const
{
bool sizeConsistent = isSizeConsistent();
bool headTailConsistent = isEndConsistent();
if (!sizeConsistent) std::cerr << "Size inconsistent" << std::endl;
if (!headTailConsistent) std::cerr << "Head / Tail inconsistent" << std::endl;
return sizeConsistent && headTailConsistent;
}
//
// Stated size is accurate to the entire list
//
bool isSizeConsistent() const
{
int count = 0;
for (Node* current = _head->_next; current != _tail; current = current->_next)
{
count++;
}
return size() == count;
}
//
// Checks that the head and tail are defaulted properly and the
// respective next pointers are appropriate.
//
bool isEndConsistent() const
{
if (_head->_data != T{}) return false;
if (_tail->_data != T{}) return false;
if (_head->_next == nullptr) return false;
if (_tail->_next != nullptr) return false;
if (isEmpty() && _head->_next != _tail) return false;
if (!isEmpty() && _head->_next == _tail) return false;
return true;
}
};
#endif
Any overall suggestions for a fix?
UPDATE: This issue only appears when I use the binary tree for strings. If I feel it with ints, everything works fine!
A few months ago I wrote a Binary Tree implementation in C++. Everything seemed to work okay (insert, remove, traversals, find...) and I passed my exams :) But now when I write a new class based on this binary tree class, the find method seems to be buggy, but I can't find the reason.
Here is the issue: find returns a pointer to a node, but for some reason I can access its member variables only when this node is the root. I can't quite understand why. Something to do with poiters? Or is there something wrong in my insert function? Can someone help me, because I feel a bit lost :)
Here is my Binary Tree interface:
template <class N>
class Node {
public:
N data;
Node* left;
Node* right;
Node* parent;
};
template <class B>
class BinaryTree {
protected:
Node<B>* m_root;
unsigned int m_height; // longest path in tree
unsigned int m_size; // total number of nodes
// methods that support public methods of below
void __insert(Node<B>* element, B value);
void __inorder(Node<B>* element);
void __preorder(Node<B>* element);
void __postorder(Node<B>* element);
void __remove(Node<B>* element, B value);
void __update_parent(Node<B> *element);
void __destroy_tree(Node<B>* element);
int __get_height(Node<B>* element);
Node<B>* __find(Node<B>* element, B value);
Node<B>* __find_minimal(Node<B> *element);
public:
BinaryTree(); // Default constructor
~BinaryTree(); // Default deconstructor
void insert(B value);
void inorder();
void preorder();
void postorder();
void remove(B value);
int get_size();
int get_height();
bool is_empty();
bool find(B value);
bool check_find(B value);
};
Insert:
template <class B>
void BinaryTree<B>::insert(B value) { // Creates a new node in the tree with value
if(m_root == NULL) {
m_root = new Node<B>; // creating the root if it's empty
m_root->data = value;
m_root->left = NULL;
m_root->right = NULL;
m_root->parent = NULL;
}
else {
Node<B>* element = m_root;
__insert(element, value);
}
}
template <class B>
void BinaryTree<B>::__insert(Node<B>* element, B value) {
if(value < element->data) {
if(element->left != NULL)
__insert(element->left, value);
else {
element = element->left;
element = new Node<B>;
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element;
m_size++;
}
}
else if(value >= element->data) {
if(element->right != NULL)
__insert(element->right, value);
else {
element = element->right;
element = new Node<B>;
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element;
m_size++;
}
}
}
Find:
template <class B>
Node<B>* BinaryTree<B>::__find(Node<B>* element, B value) {
if(element != NULL) {
if(value == element->data)
return element;
else if(value < element->data)
__find(element->left, value);
else if(value > element->data)
__find(element->right, value);
}
else
return NULL;
}
Finally, a function that tests find. Even if the values match, it returns only True when the found node is m_root. Why?
template <class B>
bool BinaryTree<B>::check_find(B value) {
Node<B>* node = __find(m_root, value);
if(node != NULL && node->data == value)
return true;
return false;
}
Why?
More links:
Full code of my Binary Tree implementation:
https://github.com/vgratian/CS-121-Data-Structures/tree/master/graphs
Program where I use this Binary Tree:
https://github.com/vgratian/rate-ur-prof
The problem lies with your find implementation:
else if(value < element->data)
__find(element->left, value);
else if(value > element->data)
__find(element->right, value);
This only works for types/classes for which the relational operators < and > are defined (in a relevant way). So it will not work whe B is an std::string for example.
For string matching, consider using a Trie.
in your insert function, you don't actually insert the element into the tree.
you create a new node, and set it's parent to point to itself. also, you didn't updated the parent left/right pointers to the new node.
take a look in the added comments:
if(element->left != NULL)
__insert(element->left, value);
else { // meaning element->left == NULL
element = element->left; // element = NULL
element = new Node<B>; // element = new node
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element; // element->parent = new node.element parent point to himself