I'm trying to build a function to insert into a binary search tree, but I'm having a hard time figuring out why it won't work. I understand fundamentally how the function is supposed to work, but based on the template I was given it seems as though I am to avoid creating a BST class but instead rely on the Node class and build the desired functions to work on that. Here's the given template:
#include <iostream>
#include <cstddef>
using std::cout;
using std::endl;
class Node {
int value;
public:
Node* left; // left child
Node* right; // right child
Node* p; // parent
Node(int data) {
value = data;
left = NULL;
right = NULL;
p = NULL;
}
~Node() {
}
int d() {
return value;
}
void print() {
std::cout << value << std::endl;
}
};
function insert(Node *insert_node, Node *tree_root){
//Your code here
}
The issue I'm having is when I implement the following code, where getValue is a simple getter method for Node:
int main(int argc, const char * argv[]) {
Node* root = NULL;
Node* a = new Node(2);
insert(a, root);
}
void insert(Node *insert_node, Node *tree_root){
if (tree_root == NULL)
tree_root = new Node(insert_node->getValue());
The code appears to compile and run without error, but if I run another check on root after this, it returns NULL. Any idea what I'm missing here? Why is it not replacing root with a new node equal to that of insert_node?
I also realize this doesn't appear to be the optimal way to implement a BST, but I am trying to work with the template given to me. Any advice would be appreciated.
As Joachim said your issue relates to difference between passing parameter by reference and by value.
In your code void insert(Node *insert_node, Node *tree_root) you pass Node* tree_root by value. Inside the function you change local copy of this pointer, so outer value is not changed.
To fix it you should pass Node* tree_root by reference. Parameter declaration can be Node*& tree_root (or Node** tree_root). E.g:
void insert(Node* insert_node, Node*& tree_root){
if (tree_root == NULL)
tree_root = new Node(insert_node->getValue());
Related
This question already has answers here:
Binary Search Tree Destructor
(6 answers)
Closed 2 years ago.
Please help me. I am stuck at this.
What am I trying to do: Binary search tree.
I am a C# developer and I learn C++ for about 2 weeks, therefore don't be so harsh with me and that's why pointers are still difficult for me.
I have a struct Node
struct Node
{
int Value;
Node* _LeftNode;
Node* _RightNode;
Node(int value)
: Value(value), _LeftNode(NULL), _RightNode(NULL)
{
}
};
and a Delete() function in BinarySearchTree.cpp
void BinarySearchТрее::Delete(Node* node)
{
if (node)
{
Delete(node->_LeftNode);
Delete(node->_RightNode);
delete(node);
node = NULL;
}
}
I want to delete the node and all of its child nodes.
When I first step in the recursion... For example:
I have two child nodes with values 10 and 19.
With recursion, I delete the nodes and set the pointers to NULL.
And here is the problem:
When I came out from the recursion the nodes are not NULL, but something strange.
And this is my problem. Why when I am in the recursion and I NULL the pointer everything is fine, but when I come out the pointer is something else.
As I talked in the comments, I think the thing is that how we can reset the pointer of the parent's(left or right child) of the initially passed node. (recursively deleting a node and its all children looks good.)
And I don't think it is possible in your current design. As Node does not contain a pointer to its parent, so there is no way to know who's the parent. node = NULL sets just the argument(local variable)'s value so it is pointless.
The C++ way would be to use std::unique_ptr.
struct Node
{
int Value;
std::unique_ptr<Node> LeftNode;
std::unique_ptr<Node> RightNode;
Node(int value)
: Value(value)
{
}
};
Then to destroy a node and all of its children, you'd call reset on the appropriate std::unique_ptr<Node>
I think what you actually want ist this:
struct Node
{
int Value;
Node* _LeftNode;
Node* _RightNode;
Node(int value)
: Value(value), _LeftNode(NULL), _RightNode(NULL)
{
}
~Node() {
delete _LeftNode;
delete _RightNode;
}
};
This way you are using the destructor to clean up recursivly.
delete nullptr is ok btw.
EDIT:
the unique_ptr<> usage in one of the other answers is probably the smarter way to do this.
Given:
struct Node
{
int data = 0;
struct Node * left = nullptr, * right = nullptr;
Node(int data) { this->data = data; }
};
This recursive function deletes a node & its childs (+ one comment):
void DeleteTree(struct Node* node) // A copy of the caller pointer
{
if (node)
{
DeleteTree(node->left); // Recur on left subtree
DeleteTree(node->right); // Recur on right subtree
delete node;
// node = nullptr; <-- This line is useless
}
}
To your wondering "but when I come out the pointer is something else":
There is no point in node = nullptr line, since when you call DeleteTree(my_node) function, node is a copy of my_mode, so when you set node = nullptr it has no effect on my_node that on exit from DeleteTree(my_node) points to a deleted, invalid object.
--
Possible solution:
#define DELETE_TREE(node) DeleteTree(node); node = nullptr; // Macro
int main()
{
struct Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
DELETE_TREE(root->left); // root->left became nullptr
DELETE_TREE(root); // root became nullptr
return 0;
}
After DeleteTree function, the caller pointer points to an invalid object since its object already released. A possible solution is to define a DELETE_TREE Macro to "auto-nullify" the caller pointer after DeleteTree function.
--
Implementation with Modern C++ Smart Pointers:
#include <memory>
struct Node
{
int data = 0;
std::unique_ptr<Node> left, right;
Node(int data) { this->data = data; }
};
int main()
{
std::unique_ptr<Node> root;
root = std::make_unique<Node>(1);
root->left = std::make_unique<Node>(2);
root->right = std::make_unique<Node>(3);
root->left->left = std::make_unique<Node>(4);
root->left->right = std::make_unique<Node>(5);
root.reset();
return 0;
}
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
...
}
Hi I am trying to create a function that counts the number of nodes in the binary tree. I am getting an error that says mismatch of functions. I have gotten other errors and can't seem to get it to work. I know the idea just am having a hard time figuring this one out. Thank You! Edit - My error is mismatch of parameter list.
template<class T>
class BinaryTree
{
private:
struct TreeNode
{
T value;
TreeNode *left;
TreeNode *right;
};
TreeNode *root;
void insert(TreeNode *&, TreeNode *&);
void NodeNumber(TreeNode *&, int&); //My NodeNumber declaration
public:
BinaryTree()
{
root = nullptr;
}
void insertNode(T);
int NodeNum();
};
template <class T>
void BinaryTree<T>::insertNode(T item)
{
TreeNode *newNode = nullptr;
newNode = new TreeNode;
newNode->value = item;
newNode->left = newNode->right = nullptr;
insert(root, newNode);
}
template <class T>
void BinaryTree<T>::NodeNumber(TreeNode *&root, int&)
{
if (root = nullptr)
return;
else
root->right;
root->left;
count = count + 2;
}
template <class T>
int BinaryTree<T>::NodeNum()
{
int count = 0;
NodeNumber(root,count);
return count;
}
You have numerous mis-designs and errors in this class. I will focus on the outright errors. I don't know which of those mis-designs has been mandated by your professor and which are yours.
BinaryTree<T>::NodeNumber, as it is currently written, will crash every time. To figure out why, think carefully about exactly what this line does:
if (root = nullptr)
How does that line differ from these two?
root = nullptr;
if (root)
Secondly, what do the lines:
root->left;
and:
root->right;
do exactly? Why do you think they do that?
Lastly, when exactly should you be adding to count and why? Where is that true?
You didn't give a name to the 2nd parameter in this function, which I assume should be count.
// original
template <class T>
void BinaryTree<T>::NodeNumber(TreeNode *&root, int&)
{
if (root = nullptr)
return;
else
root->right;
root->left;
count = count + 2;
}
A few comments:
If you have a non-null root pointer, you want to visit both left and right child trees. It looks weird that right is in the "else" case, while left is not. I suggest getting rid of the "else" and just return if root is null, and otherwise process both left and right after the if.
You are not testing if the root pointer is null; you are setting it to null.
There is no reason to pass a reference to the root pointer
Your statements like "root->right" do not do anything. You want to recurse down the left child and recurse down the right child, so need to call NodeNumber again and pass your children as the root of these recursive calls, and also pass "count" down too.
Why do you increment by 2? Each node should only count as 1. (Its children will account for themselves as you recurse down them, so only add one for the node itself.)
I prefer to return the count rather than use an "out" parameter
Therefore, consider something like this:
template <class T>
int BinaryTree<T>::NodeNumber(TreeNode *root)
{
if (root == nullptr)
return 0;
int count = 1;
count += NodeNumber(root->right);
count += NodeNumber(root->left);
return count;
}
And of course, adjust the declaration and calls accordingly.
I have made a superclass named "tree". I have constructed the tree in this class. Now, I want to pass the root of the constructed tree to another class which is a subclass of tree. But when I try to pass it, the subclass calls the supercalss constructor and sets it to NULL;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
This is the definition of my tree class. It just creates a tree with one node having value 5. Now I want to pass the new root created to a subclass of tree.
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
I create an object for tree first and then do createtree. Now, when I create an object for treeiterator, it's member p gets sets to NULL since supercalss constructor is also called. How can I just access the tree created in the superclass in subclass?
Full code:
#include <bits/stdc++.h>
using namespace std;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
void treeiterator::push(struct node *t)
{
while(t) {
s.push(t);
t = t->left;
}
}
bool treeiterator::hasnext()
{
return s.empty()?1:0;
}
int treeiterator::next()
{
struct node *t = s.top();
int val = t->val;
s.pop();
if(t->right) {
push(t->right);
}
return val;
}
int main()
{
tree t;
t.createtree();
t.preorder();
treeiterator it;
while(it.hasnext()) {
cout<<it.next()<<' ';
}
}
Because of inheritance every treeiterator is also a tree. This means
treeiterator treeIt;
treeIt.createtree();
will do what OP wants. There is no need to make a separate tree and moving the root around.
However this is a bit odd in the world of C++ because OP is under-using the constructor. For example, node could be:
struct node
{
node *left;
node *right;
int val;
node(int inval):
val(inval),
left(nullptr),
right(nullptr)
// the above is a Member Initializer List. It makes sure all of your
// members are initialized before the body of the constructor runs.
{
}
};
That bit after the : in the constructor is the Member Initializer List.
Now when you allocate a node it's initialized and ready to be linked. For tree
class tree
{
public:
struct node *root; // almost certainly should not be public.
// also should be a std::unique_ptr<node>
tree(int inval)
{
root = new node(5); // note new in place of malloc. new allocates
// storage and calls constructors. malloc should
// only be used in C++ in rare edge-cases.
}
/* obsolete
void createtree()
{
root = create(5);
}
*/
...
};
tree is assigned a root on allocation. treeiterator is a wee bit trickier because it must call tree's constructor to set up root.
class treeiterator:public tree
{
struct node *p; // Don't see the point off this
stack<struct node *> s; // or this, but that's another question
public:
treeiterator(int inval):
tree(inval) // call's tree's constructor
{
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
Allocating a treeiterator now guarantees that it is all ready to go with no further work.
treeiterator treeIt(5); // all done.
All of the above is covered within the first few chapters of any good C++ programming text. I recommend getting one and reading it, because right now it looks like you are trying to write bad C.
Off topic 1:
You are going to quickly find that this code is in violation of the Rule Of Three. What is The Rule of Three? If you don't know, read the link. It will save you much time and hair-pulling
Off Topic 2:
#include <bits/stdc++.h>
using namespace std;
Is a ticking time bomb. The first line includes the entire standard library, but only in GCC. Your code is now doing far, far more work than it need to to compile, is no longer standard C++, and is not portable to other compilers and may well break with the next revision of GCC. Don't use anything in bits. It internal compiler-specific stuff with no guarantees what-so-ever.
More here: Why should I not #include <bits/stdc++.h>?
The second line takes everything in the std namespace and places it in the global namespace. This leads to fun games like is reverse or std::reverse being called? Often this leads to insane and arcane compiler messages because the poor compiler is confused as hell, but sometimes it's not confused and picks the best choice among the many and silently breaks something else. Great fun debugging.
More here: Why is "using namespace std" considered bad practice?
Together you have the entire standard library pulled into your file AND stripped of it's proper namespace. This results in a vast minefield of potential hidden pain that is not worth any perceived time savings. One of the resulting bugs could cost more clean up than years of typing a few extra lines per file and characters.
No one want to clean up code with this stupid a mistake, so doing this in a professional setting can be costly.
First, you should not have root has public. This is a gross OO error. If you want it to be available to subclasses you should make it protected.
I am trying to implement a custom tree structure, but I am getting a weird output.
enum letter{B,A,T,G,C,N};
struct Node {
int ltr;
Node* ptr;
};
class GTree
{
public:
GTree(int);
void insert(int);
private:
Node* root;
void insert(int l,Node* leaf);
};
GTree::GTree(int l)
{
root->ltr=l;
}
void GTree::insert(int l, Node *leaf)
{
cout<<leaf->ltr;
}
void GTree::insert(int l)
{
if(root==NULL)
{
insert(l, root);
}
else
{
root= new Node;
insert(l,root);
}
}
int main()
{
GTree tree=GTree(T);
tree.insert(T);
}
The output comes out as -2062064467 even though I was expecting 2. Whats going on here? I was looking at a simple BTree implementation, but intending to repurpose it for my desired data structure.
You didn't create a Node object when you first created the GTree object.
GTree::GTree(int l)
{
root->ltr=l;
}
should be
GTree::GTree(int l)
{
root = new Node();
root->ltr=l;
}
Also, make sure you have a destuctor to clean up the resources.
Something else I feel I should point out is that GTree::insert(int l, Node *leaf) perhaps doesn't do what you expect it to do.
cout<<leaf->ltr;
The code above only outputs the integer value in the node but not actually assigning it.
But perhaps you haven't completed that part yet. :-)
You hadn't initialized root, so root->ltr=l; produces undefined behavior. Add root = new Node(); first.
I ran your code and got the output 0 on Ubuntu 12.04 with gcc 4.6.3.