I'm trying to work on a binary search tree data structure, but I cannot seem to accomplish inserting anything into the tree. Every time my program calls the insert function, it believes there is nothing in tree. Here are the 2 classes:
template<typename T>
class TreeNode{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
TreeNode<T>(const T& data, TreeNode<T>* right, TreeNode<T>* left) : m_data(data), m_right(right), m_left(left){};
};
template<typename T>
class MyBSTree : public AbstractBSTree<T>{
protected:
TreeNode<T>* m_root;
int m_size;
And here is the function:
void rec_insert(TreeNode<T>* root, const T& x){
if(root == NULL){
cout << "Inserting here" << endl;
TreeNode<T>* tmp = new TreeNode<T>(x, NULL, NULL);
root = tmp;
}
else if(x < root -> m_data){
cout << "Inserting left" << endl;
rec_insert(root -> m_left, x);
}
else if(x > root -> m_data){
cout << "Inserting right" << endl;
rec_insert(root -> m_right, x);
}
if(root == NULL)
cout << "WHAT IS HAPPENING?" << endl;
cout << "resizing" << endl;
m_size++;
};
The output for inserting a couple of items is this:
Inserting here
resizing
Inserting here
resizing
I really have no clue what is going on here, any help would be greatly appreciated.
You need to do a bit of research on pass by reference and pass by value.
You pass a pointer into your insert method - you can only change the value of root locally - any change you make won't persist beyond the function call. You need to pass by reference to allow root to be changed and see that change outside the rec_insert() method.
Another approach may be to refactor your code to return the root value from rec_insert().
Related
is it possible to write a function to return the parent node of a given node for a binary tree?
BinaryTree *search_val(BinaryTree *bt, int val)
{
//temp pointer
BinaryTree* temp = NULL;
if(!bt->isEmpty())
{
//check if root is equal to value and return root if true
if(bt->getData() == val)
{
return bt;
}
else
{
//search left side
temp = search_val(bt->left(), val);
//if not found in left, search right
if (temp == NULL)
{
temp = search_val(bt->right(), val);
}
return temp;
}
return NULL;
}
return NULL;
}
I just have this search function at the moment. I got it from here actually. So I'm trying to convert this to search for the parent of a node. The parameters will be the root node and the node whose parent we want. Is that even possible?
I just need some hints to get started then I'll post my code. The purpose of creating this function is because I have a delete leaf node function that works almost perfectly....the only problem is that when I print all nodes after deleting, the supposedly deleted node still appears. I'm sure it's because the parent node is still linked to it in main. Here's my delete leaf node function:
void delete_leaf_node(BinaryTree *bt, int val)
{
BinaryTree *temp;
temp = search_val(bt, val);
//If node does not exist in the tree, inform the user
if(temp == NULL)
{
cout << "\n " << val << " was not found in the tree" << endl;
}
//Check if node is a leaf
else if(temp->isLeaf())
{
delete temp;
cout << "\n Leaf " << temp->getData() << " deleted" << endl;
}
//Inform user that node is not a leaf
else
cout << "\n " << temp->getData() << " is not a Leaf" << endl;
//Display using In Order Traversal to see that the node was actually deleted
cout << "\n In Order Traversal after deleting: " << endl << "\n ";
inOrderTraverse(bt);
cout << endl;
}
I hope I'm making sense to someone...sorry I tried to shorten the question but couldn't.
BinaryTree.h file:
using namespace std;
//BinaryTree class
class BinaryTree{
public:
BinaryTree();
bool isEmpty();
bool isLeaf();
int getData();
void insert(const int &DATA);
BinaryTree *left();
BinaryTree *right();
void makeLeft(BinaryTree *bt);
void makeRight(BinaryTree *bt);
private:
bool nullTree;
int treeData;
BinaryTree *leftTree;
BinaryTree *rightTree;
};
BinaryTree.cpp file:
#include <iostream>
#include "BinaryTree.h"
using namespace std;
//constructor
BinaryTree::BinaryTree()
{
nullTree = true;
leftTree = NULL;
rightTree = NULL;
}
/*
is_empty function for BinaryTree class. Does not take any parameters.
Returns true if tree is empty and false otherwise.
*/
bool BinaryTree::isEmpty()
{
return nullTree;
}
/*
is_leaf function for BinaryTree class. Does not take any parameters.
Returns true if node has no children and false otherwise.
*/
bool BinaryTree::isLeaf()
{
return ((this->leftTree->treeData == 0) && (this->rightTree->treeData == 0));
}
/*
getData function for BinaryTree class. Does not take any parameters.
Returns treeData value.
*/
int BinaryTree::getData()
{
if(!isEmpty());
return treeData;
}
/*
insert function for BinaryTree class. Takes one parameter, passed by
reference. Returns true if node has no children and false otherwise.
*/
void BinaryTree::insert(const int &DATA)
{
//create empty children and insert DATA
treeData = DATA;
if(nullTree)
{
nullTree = false;
leftTree = new BinaryTree;
rightTree = new BinaryTree;
}
}
/*
left function for BinaryTree class. It points to the left node.
Does not take any parameters. Returns left node.
*/
BinaryTree *BinaryTree::left()
{
if(!isEmpty());
return leftTree;
}
/*
right function for BinaryTree class. It points to the right node.
Does not take any parameters. Returns right node.
*/
BinaryTree *BinaryTree::right()
{
if(!isEmpty());
return rightTree;
}
/*
makeLeft function for BinaryTree class. Takes a pointer to a tree node as a parameter.
makes the parameter the left child of a node. Does not return any value
*/
void BinaryTree::makeLeft(BinaryTree *bt)
{
if(!isEmpty());
leftTree = bt;
}
/*
makeRight function for BinaryTree class. Takes a pointer to a tree node as a parameter.
makes the parameter the right child of a node. Does not return any value
*/
void BinaryTree::makeRight(BinaryTree *bt)
{
if (!isEmpty());
rightTree = bt;
}
Thanks
That depends on your BinaryTree implementation. As far as I see, if you don't save a reference inside each node to his parent, you can't directly access to it when deleting
Edit
You can modify your BinaryTree class with:
class BinaryTree{
public:
BinaryTree();
bool isEmpty();
bool isLeaf();
int getData();
void insert(const int &DATA);
BinaryTree *left();
BinaryTree *right();
void makeLeft(BinaryTree *bt);
void makeRight(BinaryTree *bt);
void setParent(BinaryTree *parent);
BinaryTree* getParent();
private:
bool nullTree;
int treeData;
BinaryTree *leftTree;
BinaryTree *rightTree;
BinaryTree* parent;
};
Then in your .cpp:
BinaryTree::BinaryTree()
{
nullTree = true;
leftTree = NULL;
rightTree = NULL;
parent = NULL;
}
void BinaryTree::setParent(BinaryTree *parent){
this->parent = parent;
}
BinaryTree* BinaryTree::getParent(){
return parent;
}
Your delete function will look like:
void delete_leaf_node(BinaryTree *bt, int val)
{
BinaryTree *temp;
temp = search_val(bt, val);
//If node does not exist in the tree, inform the user
if(temp == NULL)
{
cout << "\n " << val << " was not found in the tree" << endl;
}
//Check if node is a leaf
else if(temp->isLeaf())
{
// You must distinguish which child you are
BinaryTree* parent = temp->getParent();
BinaryTree* leftChild = parent->left;
BinaryTree* rightChild = parent->right;
if(leftChild == temp){
parent->left = null;
}
if(rightChild == temp){
parent->right = null;
}
delete temp;
cout << "\n Leaf " << temp->getData() << " deleted" << endl;
}
//Inform user that node is not a leaf
else
cout << "\n " << temp->getData() << " is not a Leaf" << endl;
//Display using In Order Traversal to see that the node was actually deleted
cout << "\n In Order Traversal after deleting: " << endl << "\n ";
inOrderTraverse(bt);
cout << endl;
}
I'm writing a simple Binary Tree program in C++ and right now it only stores the most recent value entered at the root node eg. if I enter 10 into the tree then 9 into the tree, 9 just overwrites 10 as the root node so the tree only stores the value 9.
I've looked at multiple C++ Binary Tree solutions online and tried their version of implementing them yet I still get no success.
Here is my struct for a single node in the tree
struct TreeNode{
int value;
TreeNode *left;
TreeNode *right;
TreeNode(int value){
this -> value = value;
left = NULL;
right = NULL;
}
};
My class for the binary tree so far
class IntTree{
private :
TreeNode *root;
public :
IntTree();
TreeNode* getRoot();
void insertValue(TreeNode *root, int intValue);
TreeNode* searchTree(TreeNode *root, int intValue);
void inOrder(TreeNode *root);
void deleteValue(int intValue);
void deleteTree(TreeNode *root);
};
The Insert Method
void IntTree::insertValue(TreeNode *root, int intValue){
if(root == NULL){
root = new TreeNode(intValue);
}
else if(intValue == root->value){
cout << "Value already exists in the tree" << endl;
}
else if(intValue < root->value){
insertValue(root->left, intValue);
}
else{
insertValue(root->right, intValue);
}
}
And then this method is simply called in a menu like this
cout << "Enter Value to Insert : " << endl;
input = readInt();
theTree.insertValue(theTree.getRoot(), input);
The logic all seems fine to me, apart from that I've tried not using a constructor and just induvidually setting the variable, having two functions for inserting one with just the int parameter which so I don't have to use the getRoot() later on and a million other things which I've forgotten
The answer is simple, the pointer you are modifying is only a copy, so the copy is discarded at the end of the function and you have lost memory. You need to take a reference on the pointer to actually modify it (nothing else to modify):
void insertValue(TreeNode *& root, int intValue)
This should work:
New insertvalue function call will look as below
void insertValue(TreeNode **root, int intValue)
{
if(*root == NULL)
{
*root = newNode(intValue);
}
else if(intValue == (*root)->value)
{
cout << "Value already exists in the tree" << endl;
}
else if(intValue < (*root)->value)
{
insertValue(&(*(root))->left, intValue);
}
else
{
insertValue(&(*(root))->right, intValue);
}
}
int main()
{
//initial code
insertvalue(&root,value) //root is a single pointer variable.
//code for printing the tree
}
There are many less complex ways to implement the same. i have just modified your code.
Ill start out with giving all the code I think is relevant. Basically a Binary Search Tree was already defined that worked and we need to add a parent node functionality. I have done this but I keep getting segmentation faults.
template <class TKey>
class bst {
private:
struct node {
node() { key=TKey(); link[0]=link[1]=NULL; parent=NULL; }
operator TKey () { return key; }
void print();
TKey key;
node *link[2];
node *parent;
};
public:
class iterator {
public:
private:
friend class bst<TKey>;
node *p;
};
node *prev_node;
iterator begin() { }
iterator end() { }
bst() { Troot=NULL; }
~bst() { clear(Troot); }
bool empty() { return Troot==NULL; }
void clear() { clear(Troot); Troot=NULL; }
void erase(TKey &key);
void insert(TKey &key);
void print_inorder() { print_inorder(Troot); }
void print_bylevel();
private:
void clear(node *);
node *minmax_key(node *, int);
node *erase(node *, TKey &);
node *insert(node *, TKey &);
void print_inorder(node *);
node *Troot;
};
Thats the Class Definition.
template <class TKey>
void bst<TKey>::insert(TKey &key)
{
Troot = insert(Troot, key);
}
template <class TKey>
class bst<TKey>::node *bst<TKey>::insert(node *T, TKey &key)
{
cout << "insert1" << endl;
if (T == NULL) {
T = new node;
T->key = key;
if (prev_node != NULL)
T->parent = prev_node;
cout << T->parent->key;
} else if (T->key == key) {
cout << "key " << key << " already in tree" << endl;
} else {
prev_node = T;
int dir = T->key < key;
T->link[dir] = insert(T->link[dir], key);
}
return T;
}
These are the insert functions. Im guessing I am doing something out of order because I am still really rusty with recursion. When I run the test program that uses the tree it outputs the inser1 line but then gives a seg fault. So i know it is messing up on the first insert. any help? If you need to see the rest of the code I can put it up but itll be a lot of stuff that isnt actually relevent to the changes Ive made.
I'm thinking the segfault is on this line
cout << T->parent->key;
If T->parent is null, which it is if T is the newly created root (ie if prev_node == NULL), then you can't access the 'key' of a NULL value.
NOTE: Be aware that I have only skimmed your code, so this is only the first thing I have come across, there could be other bugs.
EDIT:
What do you mean by "I am still having problems", what problems are you having?
It probably isn't how I would implement a BST insert but I can't see anything jumping out saying it is wrong.
How I would implement it is rather than having a global variable prev_node, I would probably change your code like so:
template <class TKey>
void bst<TKey>::insert(TKey &key)
{
// Note that I have an initial prev_node of NULL
Troot = insert(Troot, key, NULL);
}
// Note the extra function parameter
template <class TKey>
class bst<TKey>::node *bst<TKey>::insert(node *T, TKey &key, node *prev_node)
{
cout << "insert1" << endl;
if (T == NULL) {
T = new node;
T->key = key;
// I have a habit of always using braces, so that it is easier to read.
// This would have helped you with your initial problem.
if (prev_node != NULL) {
T->parent = prev_node;
}
//cout << T->parent->key;
} else if (T->key == key) {
cout << "key " << key << " already in tree" << endl;
} else {
int dir = T->key < key;
T->link[dir] = insert(T->link[dir], key, T); // Note diff here
}
return T;
}
Unless you are using prev_node somewhere else.
But this shouldn't change how the insert works, unless in your implementation:
prev_node is not null initially for some reason (which would be the case on successive inserts, unless you are resetting it somewhere else).
something is changing prev_node while you are using it (think thread-safety)
I've been practicing my C++, as it's gotten a little rusty since college, and I'm having a bizarre problem where a member value is being overwritten as soon as my function returns.
template <class T>
class BstNode
{
public:
T value;
BstNode<T>* left;
BstNode<T>* right;
BstNode<T>* parent;
BstNode()
{ left = right = parent = NULL; }
BstNode(T value)
{ this->value=value; left=right=parent=NULL;}
BstNode(T value, BstNode<T>* parent)
{ this->value=value; this->parent=parent; left=right=NULL;}
};
template <class T>
class BinarySearchTree
{
protected:
BstNode<T>* root;
void removeNode(BstNode<T>* node);
void addChild(T value, BstNode<T>* node);
BstNode<T>* find(T value, BstNode<T>* node);
public:
BinarySearchTree()
{ root = NULL; }
~BinarySearchTree()
{ removeNode(root); }
BinarySearchTree<T> insert(T value);
bool contains(T value);
BinarySearchTree<T> remove(T value);
void print();
BstNode<T>* getRoot() {return root;}
};
template <class T>
BinarySearchTree<T> BinarySearchTree<T>::insert(T value)
{
if (root == NULL)
{
root = new BstNode<T>(value);
}
else
{
addChild(value, root);
}
cout << "VAL: " << root->value << endl << "LEFT: " << root->left << endl << "RIGHT: "<< root->right << endl << "ADDR: " << root <<endl;
return *this;
}
template <class T>
void BinarySearchTree<T>::addChild(T value, BstNode<T>* node)
{
if (value > node->value)
{
cout <<"\tgt"<<endl;
if (node->right == NULL)
{
node->right = new BstNode<T>(value, node);
}
else
{
addChild(value, node->right);
}
}
else
{
cout<<"\tlte"<<endl;
if (node->left == NULL)
{
node->left = new BstNode<T>(value, node);
}
else
{
addChild(value, node->left);
}
}
}
// [other member functions]
int main()
{
BinarySearchTree<int> tree;
BstNode<int> *n;
n = tree.getRoot();
cout << "ADDR: " << n <<endl<<endl;
tree.insert(5);
n = tree.getRoot();
cout << "VAL: " << n->value << endl << "LEFT: " << n->left << endl << "RIGHT: "<< n->right << endl << "ADDR: " << n << endl;
return 1;
}
The output of my function is:
$ ./bst
ADDR: 0
VAL: 5
LEFT: 0
RIGHT: 0
ADDR: 0xa917c8
VAL: 11085080
LEFT: 0xa917a8
RIGHT: 0
ADDR: 0xa917c8
I don't understand why the values in the root node changed, but the pointer is still pointing at the same location. The only thing I could think of is that the root node is being created on the stack instead being allocated in the heap, but doesn't new make sure that memory is allocated correctly in C++?
I think the issue is that your insert method returns the BinarySearchTree by value, but you don't have a copy constructor defined. As a result, this makes a shallow copy of the BinarySearchTree, returns it, and causes the copy's destructor to fire. This then deletes the BstNode stored as the root, but since the copied BinarySearchTree shares BstNodes with the original tree, you're trashing memory in the original tree. The error you're getting is from accessing deallocated memory when you try to access the node again.
To fix this, either have the insert function return a reference to the tree (so no copy is made) or define a copy constructor or assignment operator. Ideally, do both. :-)
Hope this helps!
So my code is below. I'm not getting any errors and it places everything in the node just fine. But based on my debug statements Everytime anything is inserted it's finding the root. I'm not sure if that is right. But according to output file for the assignment, my answers are different when it comes to the height of the tree, the traversals, and I just flat am still having troubles with my leaf count function. Another story though.
Based on the debug statements it looks like everything is going right where they should. But I figure I might need fresh eyes. I don't see how my traversals could change at all since it is really only a matter of where I'm proccessing the node that should effect the Inorder, preorder, and postorder.
template <class T>
void BT<T>::insert(const T& item)
{
Node<T>* newNode;
newNode = new Node<T>(item);
insert(root, newNode);
}
template <class T>
void BT<T>::insert(struct Node<T> *&root, struct Node<T> *newNode)
{
if (root == NULL)
{
cout << "Root Found" << newNode->data << endl;
root = newNode;
}
else
{
if (newNode->data < root->data)
{
insert(root->left, newNode);
cout << "Inserting Left" << newNode-> data << endl;
}
else
{
insert(root->right, newNode);
cout << "Inserting Right" << newNode->data << endl;
}
}
}
My height function is as follows just in case my insert is actually fine.
template <class T>
int BT<T>::height() const
{
return height(root);
}
template <class T>
int BT<T>::height(Node<T>* root) const
{
if (root == NULL)
return 0;
else
{
if (height(root->right) > height(root->left))
return 1 + height(root-> right);
return 1 + height(root->left);
}
}
You need to change the wording of your debug statements
Really it should read (not Root node)
cout << "Leaf Node Found" << newNode->data << endl;
It is only the root when it is first called after that any call with node->left or node->right makes it an intermediate node.
To write height() I would do this:
template <class T>
int BT<T>::height(Node<T>* root) const
{
if (root == NULL) {return 0;}
return 1 + max(height(root->left),height(root->right));
}
You need to start off with your root init'd to null. Also, you are passing *&node in; it should be *node. Else you're passing a pointer to the address(or reference, I'm not sure which in this context, but both aren't going to be right). You should be passing a pointer to Node in, not a reference.
template <class T>
void BT<T>::BT()
{ root = 0;}
template <class T>
void BT<T>::insert(const T& item)
{
Node<T>* newNode;
newNode = new Node<T>(item);
insert(root, newNode);
}
template <class T>
void BT<T>::insert(struct Node<T> *root, struct Node<T> *newNode)
{
/*stuff*/
}
#Vlion:
It should be a pointer to the left/right/root pointers (i.e. a double pointer), so the posted code is correct, although somewhat unclear.
#Doug:
Consider changing your insert function thus:
template <class T>
void BT<T>::insert(struct Node<T>** root, struct Node<T>* newNode)
{
if (*root == NULL)
{
cout << "Root Found" << newNode->data << endl;
*root = newNode;
}
It makes clear your intention that you'll be changing the pointer passed as the first parameter (or rather, the pointer whose address will be passed as the first parameter.) It will help avoid confusion such as the one that just happened.
The calls to this insert(), such as:
insert(&root, newNode);
will also reflect your intention of changing the pointer's value. This is a matter of style, though, so I can't argue if you don't want to change.
As for checking whether the tree is "correct," why not draw it out and see for yourself? Something along the lines of:
template class<T>
void printTree(struct Node<T>* node, int level=0)
{
if (!node) {
for (int i=0; i<level; ++i)
cout << " ";
cout << "NULL" << endl;
return;
}
printTree(node->left, level+1);
for (int i=0; i<level; ++i)
cout << " ";
cout << node->data << endl;
printTree(node->right, level+1);
}
(Untested code)