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!
Related
I am trying to build a basic Binary search tree in C++ and running into some problems, specifically when I try to insert a node via function and read, it gives me segmentation fault. But the same node struct works perfectly fine when I manually insert it.
The code for BST insert is as follows, and is most likely the culprit:
void BST::insert(Node* temproot,int val){
// std::cout << root->value <<std::endl;
if(!temproot){
Node* newNode = new Node;
newNode->value = val;
temproot = newNode;
std::cout << "Added Node with Value: " << val << std::endl;
return;
}
if(val<(temproot->value)){
std::cout << "LEFT" << std::endl;
insert(temproot->left, val);
}else{
std::cout << "RIGHT" << std::endl;
insert(temproot->right, val);
}
}
The node structure looks like this:
struct Node{
int value;
Node* left = nullptr, *right = nullptr;
};
And the BST class looks something like below:
class BST{
public:
Node* root= new Node;
BST(int val){
root->value = val;
}
void insert(Node*,int val);
void insertStart(int vasl){
Node* temproot = root;
insert(temproot, vasl);
}
void print(Node*);
void _print(){
print(root);
}
};
When I try to print it as follow, it gives me segmentation fault:
void BST::print(Node* temp){
std::cout << temp->value << std::endl;
temp = temp->left;
std::cout << (temp->value) << std::endl;
}
I am a bit new to C++ and am having struggle pin pointing it for couple of days. Can someone help me figure out what I am doing wrong here?
The function deals with a copy of the passed to it pointer to node. So changing a copy does not influence on the original pointer.
You have to pass a pointer to node to the function by reference.
The function declaration can look the following way
void insert(Node* &temproot,int val);
and call it like
void insertStart(int vasl){
insert( root, vasl );
}
without an intermediate pointer.
And you should declare this function as a provate static function of the class.
And initialize the data member root by nullptr.
For example
class BST{
public:
Node* root = nullptr;
BST(int val){
insert( root, val );
}
void insertStart(int vasl){
insert( root, vasl);
}
void print(Node*);
void _print(){
print(root);
}
private:
static void insert(Node* &,int val);
};
Basically, SEGFAULT comes from print function which should look like this:
void BST::print(Node* temp){
if (nullptr == temp) {
return;
}
print(temp->left);
std::cout << temp->value << std::endl;
print(temp->right);
}
And your insert function should look like this:
void BST::insert(Node *&temproot,int val){
if(nullptr == temproot){
Node* newNode = new Node;
newNode->value = val;
temproot = newNode;
return;
}
if(val < (temproot->value)){
insert(temproot->left, val);
}else{
insert(temproot->right, val);
}
}
Check it out live
please don't dig into me too hard, I am still steadily learning and ran into an issue when trying to construct an AVL tree. When iterating through the tree on insert, I go until I reach a nullptr, create a new node, and assign that ptr to the nullptr. The value is never accepted though. Can someone find the error and explain it to me? ty!
#ifndef AVLTree_hpp
#define AVLTree_hpp
#include <stdio.h>
#include <stack>
template<typename T>
class AVLTree{
private:
struct Node{
T val;
Node* left;
Node* right;
int height;
Node(T V)
:left{nullptr},right{nullptr}
{
val = V;
}
~Node(){
}
};
Node* head;
void rightRotate(Node*& node);
void leftRotate(Node*& node);
void leftRight(Node*& node);
void rightLeft(Node*& node);
public:
AVLTree();
~AVLTree();
AVLTree(const AVLTree &c);
AVLTree(AVLTree &&c);
AVLTree &operator=(const AVLTree &c);
AVLTree &operator=(AVLTree &&c);
void add(T value);
int getHeight(Node* n);
};
template <typename T>
AVLTree<T>::AVLTree()
:head{nullptr}{
}
template <typename T>
AVLTree<T>::~AVLTree(){
}
template <typename T>
void AVLTree<T>::rightRotate(Node*& node){
Node* temp = node;
node = node->left;
Node* leftLL = node->right;
temp->left = leftLL;
node->right = temp;
}
template <typename T>
void AVLTree<T>::leftRotate(Node*& node) {
Node* temp = node;
node = node->right;
Node* yL = node->left;
temp->right = yL;
node->left = temp;
}
//left right condition
template <typename T>
void AVLTree<T>::leftRight(Node*& node) {
leftRotate(node->left);
rightRotate(node);
}
//right left condition
template <typename T>
void AVLTree<T>::rightLeft(Node*& node){
rightRotate(node->right);
leftRotate(node);
}
template <typename T>
void AVLTree<T>::add(T value){
if(head==nullptr){
head = new Node(value);
return;
}
std::stack<Node*> st;
Node* it = head;
while(it!=nullptr){
st.push(it);
if(value <= it->val){
it = it->left;
}else{
it=it->right;
}
}
//here is where the it is not assigned to the new node pointer.
//I have tested it and the node is created, "it" just does not hold the value at any point.
it = new Node(value);
int count = 0;
while(!st.empty()){
int balance = getHeight(st.top()->left) - getHeight(st.top()->right);
if(balance > 1){
if(st.top()->left!= nullptr&&st.top()->left!=nullptr){
leftRotate(st.top());
}else{
leftRight(st.top());
}
}else if(balance<-1){
if(st.top()->right!=nullptr&&st.top()->right!=nullptr){
rightRotate(st.top());
}else{
rightLeft(st.top());
}
}
st.pop();
if(++count==4){
break;
}
}
}
template <typename T>
int AVLTree<T>::getHeight(Node* n){
int max =0;
if(n!=nullptr){
max = std::max(getHeight(n->left),getHeight(n->right))+1;
}
return max;
}
#endif /* AVLTree_hpp */
It is a copy of the pointer and updating it has no effect on the original pointer. You need to do something like this instead:
Node* it = head;
bool left = true;
while(it!=nullptr){
st.push(it);
left = value <= it->val;
if(left){
it = it->left;
}else{
it=it->right;
}
}
it = new Node(value);
if (left){
stack.top()->left = it;
} else {
stack.top()->right = it;
}
Consider this simplified version of your code:
#include <iostream>
struct Linked {
Linked* next;
};
int main(int argc, char** argv) {
Linked l0 {nullptr};
// Case 1: Does not work
std::cout << "case 1" << std::endl;
Linked* node = l0.next;
node = new Linked {nullptr};
std::cout << "node=" << std::hex << node << std::endl;
std::cout << "l0.next=" << std::hex << l0.next << std::endl;
free(node);
std::cout << std::endl;
// Case 2: Works
std::cout << "case 2" << std::endl;
l0.next = new Linked {nullptr};
std::cout << "l0.next=" << std::hex << l0.next << std::endl;
free(l0.next);
l0.next = nullptr;
std::cout << std::endl;
// Case 3: Works
std::cout << "case 3" << std::endl;
Linked** nodeP = &(l0.next);
*nodeP = new Linked {nullptr};
std::cout << "*nodeP=" << std::hex << *nodeP << std::endl;
std::cout << "l0.next=" << std::hex << l0.next << std::endl;
free(l0.next);
l0.next = nullptr;
}
Which outputs:
$ ./main
case 1
node=0x7fba0d400620
l0.next=0x0
case 2
l0.next=0x7fba0d400620
case 3
*nodeP=0x7fba0d400620
l0.next=0x7fba0d400620
Case 1: does not work because the new Node is assigned to a copy of the left/right child pointer (i.e. not the actual child node from the parent node)
Case 2: works as expected because the new node is assigned directly to one of the parent's child node.
Case 3: also works because instead of assigning the new node to a copy of the child pointer, you assign it to a pointer referencing the pointer to child itself. In this respect, case 2 and 3 are equivalent.
I am new to programming in C++ but I am trying to create a Binary Search Tree.
The program seems to compile fine but it gives me this error:
Unhandled exception at 0x009229B7 in Lab001_CS3.exe: 0xC00000FD: Stack
overflow (parameters: 0x00000001, 0x00AD2FBC).
when I try to run it. The error occurs on this line of code:
void insert(int value) {
...
}
I am not sure what I am doing wrong, and I have never gotten this error before.
Here is the code:
#include <iostream>
using namespace std;
//create a node struct
struct node {
//member variables
int key;
node* left;
node* right;
//default constructor
node() {
key = 0;
left = NULL;
right = NULL;
cout << "a new node is created" << endl;
}
//constructor so can create a node in one line
node(int k) {
key = k;
left = NULL;
right = NULL;
cout << "a new node is created" << endl;
}
};
class Tree {
public:
//root node
node root;
//default constructor
Tree() {
root.key = 0;
root.left = NULL;
root.right = NULL;
}
//constructor to create the root node
Tree(int data) {
//set the data to the key
//set the right and left pointers to null
root.key = data;
root.left = NULL;
root.right = NULL;
}
//print the root node
void printRootNode() {
cout << "Root Node - Key: " << root.key << endl;
}
//insert functions
void insert(int value) {
/* If the newNode's key is less than the root key, traverse left
*/
if (value < root.key) {
/* if the left node is NULL */
if (root.left == NULL) {
root.left = new node(value);
cout << "assigned left" << endl;
}
else {
/* if the left node is important */
insert(value);
cout << "recurse" << endl;
}
}
if (value > root.key) {
/* if the right node is NULL */
if (root.right == NULL) {
root.right = new node(value);
cout << "assigned right" << endl;
}
else {
/* if the right node is important */
insert(value);
cout << "recurse" << endl;
}
}
}
};
//print inorder
void inorder(node* rt) {
//base
if (rt == NULL) {
return;
}
inorder(rt->left);
cout << " " << rt->key << endl;
inorder(rt->right);
}
int main() {
//create a tree for a root node
Tree t(16);
t.printRootNode();
//create newNode
node n1(20);
node n2(31);
//insert the new nodes
t.insert(20);
t.insert(31);
//keep the window from closing
system("pause");
}
Thank you for any help.
In your insert()
if (value < root.key) {
/* if the left node is NULL */
if (root.left == NULL) {
root.left = new node(value);
cout << "assigned left" << endl;
}
else {
/* if the left node is important */
insert(value);
cout << "recurse" << endl;
}
}
let's take this go left snippet as example, if root.left != NULL the code will enter else block and recursively call insert(value) forever, which cause stack overflow, the correct operation is make current node move to root.left, and then call insert(value) recursively.
also you don't need node class at all, tree class can do all the things.
again, here is not a good place for help you debug, you need to learn how to do this yourself :-).
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;
}
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)