Recursively inserting into a binary tree, passing pointer by value? - c++

Here is my Node class.
class Node
{
private:
public:
T data;
Node<T>* left;
Node<T>* right;
Node(T dat) : data(dat), left(NULL), right(NULL)
{}
};
Here is my insert function, defined in my Btree class:
public:
Node<T>* root;
Btree() : root(NULL){}
void insert(T data, Node<T>* parent)
{
if( !parent )
{
parent = new Node<T>(data);
return;
}
else if(data < parent->data)
{
insert(data, parent->left);
}
else if(data > parent->data)
{
insert(data, parent->right);
}
}
};
Here is my main function:
int main()
{
Btree<int> tree;
tree.insert(5, tree.root);
cout << tree.root->data << endl;
tree.insert(6, tree.root);
cout << tree.root->right->data << endl;
}
When I run, I get a seg fault.
I think it is because the pointer variable parent is passed by value, so when I create a new Node that is pointed to by parent, once I exit the insert function I lose it? Does that mean I have to use a double pointer here?
Can someone give me a thorough explanation about what's going on in memory that is making this not work out as planned. Is my diagnosis correct here or is there something else wrong?
When I pass tree.root as the second parameter to insert, I am passing a Node*, I know that much. Now, even if it is passed by value, will it not be the same address that I passed from the invoking main function. So when I say parent (which is the address which I passed from main, tree.root) = new Node, should that not create a new Node on the heap that at the address of parent, aka the address of tree.root? Why does passing by value fudge this up?

The problem with passing by value in this case is that all assignments made to the formal argument inside the function are not visible to the caller. Therefore, this assignment
if( !parent )
{
parent = new Node<T>(data); // <<== HERE
return;
}
has no effect on the tree.root in the caller:
tree.insert(5, tree.root);
The value of the parent pointer in the function is changed, and then promptly discarded; tree's root remains NULL.
A fix to this problem would be passing a pointer to a pointer, like this:
void insert(T data, Node<T>** parent) {
if( !*parent )
{
*parent = new Node<T>(data);
return;
}
else if(data < (*parent)->data)
{
insert(data, &((*parent)->left));
}
else if(data > (*parent)->data)
{
insert(data, &((*parent)->right));
}
}

C++ passes by value, so that parent is a copy of the passed-in pointer. Assigning to it therefore has no lasting effect. The easiest way to fix this is to change the signature of the method so that it accepts a reference to the pointer. This will automatically make the compiler update the original pointer while avoiding having to the change the rest of the program.

dasblinkenlight answered it best. But, there is a more succinct solution:
Get the reference of the pointer (known as reference to pointer):
void insert(T data, Node<T>*& parent)
{
if( !parent )
{
parent = new Node<T>(data);
return;
}
else if(data < parent->data)
{
insert(data, parent->left);
}
else if(data > parent->data)
{
insert(data, parent->right);
}
}
See more here:
http://www.codeproject.com/Articles/4894/Pointer-to-Pointer-and-Reference-to-Pointer

Related

Binary Tree with class in c++

I'm trying to write class for binary tree in c++ but I think in inserting function I have some problem it doesnt work correctly I'm begginer in c++ and I can't find the problem.
I should write this code without using "struct" it should Compeletly write with classes
I'm so sorry beacuse my code doesn't have any comment
and also sorry for bad English
Thank you very much
#include<iostream>
using namespace std;
///////////////////////////////////////////////////////////////////////////
class Tree
{
public:
Tree* left;
Tree* right;
string info;
Tree()
{
this->left=NULL;
this->right=NULL;
this->info="";
}
Tree(string info)
{
this->left=NULL;
this->right=NULL;
this->info=info;
}
Tree(string info,Tree* left,Tree* right)
{
this->left=left;
this->right=right;
this->info=info;
}
};
/////////////////////////////////////////////////////////////////////
class LinkedList
{
public:
Tree* root;
LinkedList()
{
root=NULL;
}
void mainInsert(Tree* newroot , string info)
{
if(newroot==NULL)
{
Tree* newNode = new Tree(info);
newroot=newNode;
return;
}
if(info.compare(newroot->info)==-1)
{
mainInsert(newroot->left,info);
}
else
{
mainInsert(newroot->right,info);
}
}
void mainPrintTree(Tree* newroot)
{
if(newroot==NULL)
{
return;
}
cout<<newroot->info<<endl;
mainPrintTree(newroot->left);
mainPrintTree(newroot->right);
}
void insert(string info)
{
mainInsert(this->root , info);
}
void printTree()
{
mainPrintTree(this->root);
}
};
///////////////////////////////////////////////////////////////////////////
int main()
{
LinkedList myTree;
myTree.insert("2");
myTree.insert("1");
myTree.insert("3");
myTree.insert("7");
myTree.insert("0");
myTree.printTree();
return 0;
}
Here is a (the?) culprit:
void mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
newroot = newNode; // Oops, only changing a local pointer here!
return;
}
...
It is a common error of beginners: you passed a pointer to a function, change that pointer and wonder why the original pointer is still unchanged... The reason is that apart from being able to change its pointee value, a pointer is a mere variable. So the function has its local copy of the pointer, and changing it has no effect in the caller. Here a simple way is probably to return the new root:
Tree* mainInsert(Tree* newroot, string info)
{
if (newroot == NULL)
{
Tree* newNode = new Tree(info);
return newNode;
}
// remember to return newroot in other branches...
Just use that in insert:
void insert(string info)
{
this->root = mainInsert(this->root , info);
}
But there are tons of possible improvements here, like separating the public interface from the private implementation, so I would advise you to post your code on Code Review as soon as is will work without errors...
Your mainInsert is wrong: after mainInsert(newroot->left,info);, newroot->left is not modified because that argument is passed by value (BTW read this SO article article, it's about C, not C++ but the concept is the same).
The simplest here is just to pass the node by reference, which makes your code even simpler:
void mainInsert(Tree* &subTree, string info)
{
if (subTree == NULL)
{
subTree = new Tree(info);
return;
}
if (info.compare(subTree->info) == -1)
{
mainInsert(subTree->left, info);
}
else
{
mainInsert(subTree->right, info);
}
}
I renamed the newroot parameter into subTree, because there is actually only one root per tree and every node of the tree is actually a also tree.
BTW: your question about writing this code without using struct is pointless, you don't use struct at all in your code.
Hint: try to write an iterative version of mainInsert. It's pretty simple and straightforward as the problem is not inherently recursive.

How to correctly use smart pointers inside of a class

I am creating a binary tree in C++, and I have some problems when using smart pointers inside of the node class.
When using normal pointers, everything works fine, but with smart pointers it is just not working. I think that the problem is in this line in the insert method:
'''
binaryNode* node = this; // This is working
std::shared_ptr<binaryNode> node {this}; // This throws "double free or corruption" error
std::shared_ptr<binaryNode> node = shared_from_this (); // This throws "bad weak ptr error", I am correctly inheriting from enable_shared_from_this
'''
How can I replicate binaryNode* node = this; with smart pointers?
I even tried to use public std::enable_shared_from_this<binaryNode> usuccessfully.
Thanks for your help!
Edit:
I will try to explain myself a little bit better. This is the insert() function of a binary search tree, that looks like this (this is the .cpp file):
'''
#include "binarynode.h"
binaryNode::binaryNode(int value){
this->value = value;
this->right = nullptr;
this->left = nullptr;
}
void binaryNode::insert(int value){
binaryNode* node = this;
while(true){
if(value > node->value){
if(node->right != nullptr){
node = node->right;
}else{
node->right = new binaryNode(value);
break;
}
}else if(value < node->value){
if(node->left != nullptr){
node = node->left;
}else{
node->left = new binaryNode(value);
break;
}
}else{
return;
}
}
How can I replicate this using smart pointers?
Edit 2:
This is my .h file:
'''
#ifndef BINARYNODE_H
#define BINARYNODE_H
class binaryNode
{
public:
int value;
binaryNode(int value);
binaryNode* right;
binaryNode* left;
void insert(int value);
};
#endif // BINARYNODE_H
And this is the main file:
#include <iostream>
#include "binarynode.h"
using namespace std;
void printTree(binaryNode* node){
if(node == nullptr) return;
cout << node->value << endl;
printTree(node->left);
printTree(node->right);
}
int main(){
binaryNode* bn = new binaryNode(9);
bn->insert(4);
bn->insert(20);
bn->insert(1);
bn->insert(6);
bn->insert(15);
bn->insert(170);
printTree(bn);
return 0;
}
You do not need to use shared_ptr<>.
Actually smart pointer are here to 'solve' ownership on object, thus when an object has a single owner, unique_ptr<> should be used, and when ownership is shared, shared_ptr are used. In you situation, the ownership is clear, each node owns its left and right members, thus unique_ptr can be used.
For the tree traversal problem, don't mess with smart pointers as you are not requesting any ownership, but just looking at values, thus raw pointers are ok.
So you may end up with something like this:
#include <memory>
#include <iostream>
struct binaryNode {
binaryNode(int value) : value(value) {}
void insert(int value);
int value = 0;
std::unique_ptr<binaryNode> right;
std::unique_ptr<binaryNode> left;
};
void binaryNode::insert(int value){
binaryNode* node = this;
while(true){
if(value > node->value){
if(node->right != nullptr){
node = node->right.get();
}else{
node->right = std::make_unique<binaryNode>(value);
break;
}
}else if(value < node->value){
if(node->left != nullptr){
node = node->left.get();
}else{
node->left = std::make_unique<binaryNode>(value);
break;
}
}else{
return;
}
}
}
void printTree(const binaryNode &node){
std::cout << node.value << std::endl;
if (node.left)
printTree(*node.left);
if (node.right)
printTree(*node.right);
}
int main(){
auto bn = std::make_unique<binaryNode>(9);
bn->insert(4);
bn->insert(20);
bn->insert(1);
bn->insert(6);
bn->insert(15);
bn->insert(170);
printTree(*bn);
return 0;
}
You may notice that the print does not need to take a pointer, it can work on reference.
You cannot directly convert the same raw pointer to a shared pointer more than once, because then you will have several owners that know nothing about each other, each one thinking it has full control over the object. This is why std::shared_ptr<binaryNode> node {this} gives you a double-delete.
You also cannot use shared_from_this unless there is at least one shared pointer already pointing to your object. This is why std::shared_ptr<binaryNode> node = shared_from_this () doesn't work.
If you want shared pointers, make them all shared. For example:
// binaryNode* bn = new binaryNode(9); <-- nope!
auto bn = std::make_shared<binaryNode>(9);
// binaryNode* node = this; <-- nope!
std::shared_ptr<binaryNode> node = shared_from_this();
I do not recommend using shared pointers here though. Unique pointers are more appropriate.
C++ vector can be used to support recursive data structure. It's much simpler that use smart ptr . Basicly In your Node store vector children as a member.
#include <vector>
using std::vector;
struct Node {
Node() = default;
Node(const Node &) = delete;
Node(Node &&) = default;
vector<Node> children;
};
int main()
{
Node root;
root.children.push_back(Node());
root.children.push_back(Node());
root.children[0].children.push_back(Node());
}

How to create insert function in BST without specifying root as parameter

I've been given a task to create a method of Binary Search Tree class to insert elements in the correct place in the tree. The declaration of this function is:
void BST::insert(int k)
{
}
Can someone explain why isn't a root node given as parameter ? How am i able to traverse the tree, when I do not have its root node ? Having a return type of void hints me to use the 'this' keyword
I've tried implementing the following:
void BST::insert(int k) {
while(this->root != NULL) {
if(k < this->root->value) {
this->root = this->root->leftChild;
} else {
this->root = this->root->rightChild;
}
}
this->root = new node(k);
}
This is additionnal OOP code:
struct node {
int value;
node* parent;
node* leftChild;
node* rightChild;
node (int);
int dessiner(ofstream&, int);
};
class BST {
public:
node* root;
BST();
void dessiner(string);
void swap(node*, node*);
void inserer(int);
};
EDIT: I added 2 pointers. tmp to traverse tree and P to keep track of tmp's parent node
node* tmp = this->root;
node* p = NULL;
while(tmp!=NULL) {
p = tmp;
if(k < tmp->value) {
tmp = tmp->leftChild;
} else {
tmp = tmp->rightChild;
}
}
tmp = new node(k);
tmp->parent = p;
Can someone explain why isn't a root node given as parameter ?
It is. BST::insert implicitly has a BST * parameter, named this. From there you can get at root. Note that you don't need this-> to refer to root, it is implicit in body of the member function.
Having a return type of void hints me to use the 'this' keyword
The return type has nothing to do with it.
Note that you will need to assign the new node to p's leftChild or rightChild, after insert finishes, nothing points to it.
When dealing with BSTs I usually write a public function like the one you have which calls a the private, recursive function with the root of the tree. You don't have access to the root of the tree from outside the class so it doesn't make sense for the public function to accept anything more than the element to insert.
void BST::insert(int k)
{
insert(k, root);
}
void BST::insert(int k, node* curr)
{
// logic to insert the new element
...
}
You can combine these functions with a default parameter so from outside the class you can call bst.insert(5) and curr will start out as the root of the tree.
void BST::insert(int k, node* curr = root)
{
// logic to insert the new element
...
}

Destroy entire AVL tree

I'm having a problem entirely deleting my AVL tree. I've figured out how to delete just a single node, but my destroyTree function doesn't seem to actually destroy every node recursively. What could I be doing wrong?
I have a struct nodeType<myType>
template <class myType>
struct nodeType {
myType keyValue;
int nodeHeight;
nodeType<myType> *left;
nodeType<myType> *right;
};
and I am attempted to delete all existing nodes with:
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
but this does not seem to properly delete the nodes, when checking for the height it still gives me the height before the destroy was called although crashes when attempting to print. In the main function calling destroy tree I used a simple if statement
template <class myType>
void avlTree<myType>::destroyTree()
{
destroyTree(root);
if(root == NULL)
std::cout << "destroyed" << std::endl;
}
shows that root is NOT null (yes is not printed)
Look at this piece of code:
destroyTree(root);
if(root == NULL)
std::cout << "destroyed" << std::endl;
Probably your destroyTree function has this prototype:
void destroyTree(nodeType<myType> *node);
The problem is that node cant update the caller memory address, but only the contents that caller is pointing. This means that root will never be update, i.e., its contents cant be updated to NULL.
To do that, you need a prototype that is something like that:
void destroyTree(nodeType<myType> **node);
I'm guessing you're not taking node by reference, and therefore when you set the node to NULL you're actually setting a local copy of the node to null.
Won't work because root is taken by value - will have prior value after function call:
template <class myType>
void avlTree<myType>::destroyTree(nodeType<myType>* node) // note node taken by value here
{
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
}
Will work because root is taken by reference - will be null after the function call:
template <class myType>
void avlTree<myType>::destroyTree(nodeType<myType>* &node) // note node taken by reference here
{
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
}

c++ pointer reference confusion

struct leaf
{
int data;
leaf *l;
leaf *r;
};
struct leaf *p;
void tree::findparent(int n,int &found,leaf *&parent)
This is piece of code of BST. I want to ask. why
leaf *&parent
Why we need "reference mark" here?
parent is also a leaf, why can't I just use leaf* parent?
code below for your reference. Thank you!
void tree::findparent(int n,int &found,leaf *&parent)
{
leaf *q;
found=NO;
parent=NULL;
if(p==NULL)
return;
q=p;
while(q!=NULL)
{
if(q->data==n)
{
found=YES;
return;
}
if(q->data>n)
{
parent=q;
q=q->l;
}
else
{
parent=q;
q=q->r;
}
}
}
You are passing the pointer parent in by reference, so that you can modify that pointer:
parent=q;
If you passed the pointer in by value, the modifications would be to a copy of the pointer that expires at the end of the function.
When you use REFERENCE TO POINTER, you can change the value of the pointer. You may need to use this schema in link list implementation to change the head of the list.
void passPointer(int *variable)
{
*variable = (*variable)*2;
variable = NULL; // THIS CHANGES THE LOCAL COPY NOT THE ACTUAL POINTER
}
void passPointerReference(int* &variable)
{
*variable = (*variable)*3;
variable = NULL; // THIS CHANGES THE ACTUAL POINTER!!!!
}
int main()
{
int *pointer;
pointer = new int;
*pointer = 5;
passPointer(pointer);
cout << *pointer; // PRINTS 10
passPointerReference(pointer);
cout << *pointer; // GIVES ERROR BECAUSE VALUE OF pointer IS NOW 0.
// The constant NULL is actually the number 0.
}