How to insert into Binary Search Tree - c++

I am trying to insert into a Binary Search Tree everything compiles but when I try to run the program I get Segmentation fault (core dumped) everything looks good to me and I can't find the issue. Please Help.
int main()
{
struct node
{
int item;
node *left;
node *right;
};
node * root = NULL;
int x = 9;
void BinarySearchTree::insert(x)
{
insert(x, root);
}
void insert(x, node *t)
{
if(t == NULL)
{
t-> item = x;
t->left = NULL;
t->right = NULL;
}
else if(x < t-> item)
{
insert(x, t->left);
}
else if(t->item < x)
{
insert(x, t->right);
}
else
{
;//do nothing
}
}
}

If the pointer is null, then you try to indirect through it to set the values of the non-existent node. That will cause your segfault.
You probably want to take the argument by reference, so you can update it to point to a new node if necessary:
void insert(x, node *&t)
{ // ^
if (t == nullptr) {
t = new node {x, nullptr, nullptr};
}
// the rest of the function should work as it is
}

The question is incomplete, and without context it becomes difficult to answer accurately. That being said, there is something in the code that seems unhealthy.
the
void insert(x, node *t){}
function takes a value, and a pointer to an allocated structure.
if you hand it a null value, instead of a pointer to an allocated structure, your code will attempt to assign a value to null->item which is still null. So this will give you a segmentation fault.
if(t == NULL)
{
t-> item = x;
t->left = NULL;
t->right = NULL;
}
You must decide what to do, when not handed a a pointer to a previously allocated structure.
either, throw exception, or automatically create a new object (allocate the structure), and then assign the value.
notice if you do the latter, that you will need to return the address, of the pointer, or change the parameter to become a reference to a pointer...

Related

I am not gettin how to get rid of error here

#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node()
{
data = NULL;
left = right = NULL;
}
};
Node* insertBST(Node* root, int value)
{
if (root == NULL) {
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Node* printBST(Node* root)
{
if (root != NULL) {
printBST(root->left);
cout << "\n" << root->data;
printBST(root->right);
}
}
int main()
{
Node* root = new Node;
insertBST(root, 30);
insertBST(root, 20);
insertBST(root, 40);
insertBST(root, 70);
insertBST(root, 60);
insertBST(root, 80);
printBST(root);
}
Above is the code which I wrote to implement Binary Search Tree. When I execute it, the program stops responding and closes. I tried getting help from pythontutor.com but I am not able to tackle it.What should I do to make it run without error?
here is where it stops : Click to see
Any help is appreciated,I am new to writing program.
In insertBST in the case of root == NULL you do not create a new node and attempt to modify the contents of root, as this is null it should result in an access violation or segmentation fault.
I think the reason your program is hanging instead of crashing is that you are using an online compiler that ignores invalid writes and instead allows the program to continue. This then possibly ends up with infinite recursion through the insertBST function.
To fix this you need to allocate a new node, one way would be as follows:
void insertBST(Node*& root, int value)
{
if (root == NULL) {
root = new Node();
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Note that your program leaks all the nodes that it allocates. You should write a destructor in Node which deletes all child nodes and call delete root at the end of your program. Alternatively don't use raw pointers at all and use std::shared_ptr or std::unique_ptr instead.

Creating a smart pointer in a struct?

I'm modeling a Node in a Binary Tree using a struct. In the struct, I'm trying to have a pointer to the left and right child.
The problem is, I keep running into a stack overflow due to the way I'm creating the struct. It seems the way I've been handling the smart pointers continuously allocates memory on the stack.
The exception is specifically thrown when I create theroot in my main.
I'm new to smart pointers (I've been using raw pointers which I have recently learned is bad practice in C++), and I have tried solving this issue on my own without luck.
Can someone critique my struct/smart pointer use? Many thanks.
#include <iostream>
#include <memory>
//Node struct
struct Node
{
int data;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
Node(int data) {
this->data = data;
this->left = std::make_unique<Node>(NULL);
this->right = std::make_unique<Node>(NULL);
}
};
//insert Node into binary search tree
void insert(int data, std::unique_ptr<Node>& root)
{
if (root == NULL)
{
root = std::make_unique<Node>(data);
}
else {
if (root->data > data)
{
insert(data, root->left);
}
else {
insert(data, root->right);
}
}
}
//In Order tree traversal
void inOrderTraversal(std::unique_ptr<Node>& root)
{
if (root == NULL) return;
inOrderTraversal(root->left);
std::cout << root->data << std::endl;
inOrderTraversal(root->right);
}
int main()
{
//Initialize root to NULL
std::unique_ptr<Node> root = std::make_unique<Node>(NULL);
insert(20, root);
insert(50, root);
insert(30, root);
insert(5, root);
insert(6, root);
insert(99, root);
insert(77, root);
insert(56, root);
insert(32, root);
inOrderTraversal(root);
return 0;
}
The function std::make_unique<Node> takes parameters to forward the Node constructor.
In C and C++ NULL is usually just a macro for 0.
Therefore, when you call std::make_unique<Node>(NULL); you are initializing a Node, using data = 0.
This then recursively calls this->left = std::make_unique<Node>(NULL);, causing infinite recursion and stack overflow eventually.
To solve this you can assign std::unique_ptr<Node> left = NULL.
I would also suggest using nullptr in the place of NULL because it is type safe. Simply replacing NULL with nullptr on your code gives compiler errors, helping you resolve the issue.
error: no matching constructor for initialization of 'Node'
Replace all NULL with nullptr and don't use std::make_unique(NULL);
Node::Node(int data) {
this->data = data;
this->left = nullptr;
this->right = nullptr;
}
int main()
{
//Initialize root to NULL
std::unique_ptr<Node> root = nullptr;
// other codes ..
}

Segmentation fault when using if statement with pointers (BST tree)

I'm trying to implement a binary search tree in C, more specifically looking for the predecessor. However, whenever I try to run the program I get the segmentation vault. Here's the code in question:
#include <stdio.h>
#include <stdlib.h>
struct tree
{
int a;
tree *left;
tree *right;
tree *prev;
}*root=NULL;
tree *searchSpecific (tree *root, int val)
{
tree *x=root;
if (!x)
{
return NULL;
}
else
{
while(x && val!=x->a)
{
if (val>x->a)
x=x->left;
else x=x->right;
}
}
return x;
}
int previous(tree *root, int f)
{
tree *x=searchSpecific(root,f);
if(x->left)
{
x=x->left;
while(x->right) x = x->right;
return x->a;
}
tree *temp;
do
{
temp = x;
x = x->prev;
} while(x && (x->right != temp));
return x->a;
}
The segfault appears at the if statement if(x->left) in the previous() function. I want to check if the node in question exists, but the program crashes every time and I have no idea what is wrong with it..
Since searchSpecific may return NULL, you need to protect your code from it, and check x before accessing one of its members:
tree *x=searchSpecific(root,f);
if (x != NULL && x->left)
The segmentation fault can appear due to several reasons, such as:
x is undefined, which may be caused by your *searchSpecific function
x is NULL, because your function returns a NULL pointer
x->left is NULL, which means trying to access it causes something bad to happen
So, how I'll go about doing this would be trying to check if the returned tree is null using a simple if statement as follows:
if (x == NULL) {
/* throw error or not found message */
}
I would also suggest you dynamically allocate memory for your tree before doing anything with it, by creating a reusable func like create_tree() with the following code:
tree create_tree(int data) {
tree *x;
x = malloc(sizeof(tree));
x->a = data;
x->left = x->right = x->prev = NULL;
return x;
}
Why? Note that in your code snippets, you just declare
tree *some_tree_name;
which is very dangerous every time you try to do something with it, and might lead to your code crashing on you on the do/while loop later.

C++: Pointer vs Pointer of Pointer to insert a node in a Binary Tree

I was creating a function to insert a element in a binary tree and, first, i did the following on Visual Studio 2012:
void Insert(Nodo *root, int x){
if(root == NULL){
Nodo *n = new Nodo();
n->value = x
root = n;
return;
}
else{
if(root->value > x)
Insert(&(root)->left, x);
else
Insert(&(root)->right, x);
}
}
But this same code doesn't work at Dev-C++, I need to use Pointer of Pointer to make it work, like this:
void Insert(Nodo **root, int x){
if(*root == NULL){
Nodo *n = new Nodo();
n->value = x
*root = n;
return;
}
else{
if((*root)->value > x)
Insert(&(*root)->left, x);
else
Insert(&(*root)->right, x);
}
}
Does anybody knows why it happens?
The first code should not compile. In fact it doesn't compile under MSVC 2013.
Why ?
Your node structure should be something like this:
struct Nodo {
int value;
Nodo*left, *right; // pointer to the children nodes
};
This means that (root)->left is of type Nodo*. Hence &(root)->left is of type Nodo** which is incompatible with a Nodo* argument.
Anyway, in your insert function, you certainly want to change the tree. But if you'd for example do: root = n; you would just update the root argument (pointer). This update is lost as soon as you leave the function. Here, you certainly want to change either the content of the root node or more probably the pointer to a root node.
In the second version, you pass as argument the address of a pointer to a node, and then update this pointer when necessary (expected behaviour).
Remark
The first version could be "saved", if you would go for a pass by reference:
void Insert(Nodo * &root, int x){ // root then refers to the original pointer
if(root == NULL){ // if the original poitner is null...
Nodo *n = new Nodo();
n->value = x
root = n; // the orginal pointer would be changed via the reference
return;
}
else{
if(root->value > x)
Insert(root->left, x); // argument is the pointer that could be updated
else
Insert(root->right, x);
}
}

Binary Search Tree in C++

I'm learning C++ language and I'm trying to write BST, but something goes wrong.
I try to add element to empty tree, root is NULL, but after adding element root is still NULL despite of the fact that addiing was successful (I saw it in debug mode, node is set as tmp). I have no idea why it happens.
struct Node
{
int data;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
};
Tree createTree()
{
Tree tmp;
tmp.root = NULL;
return tmp;
}
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
void add(Tree* tree, int value)
{
addToNode(tree->root, value);
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree tree = createTree();
add(&tree, 10);
printf("%d", tree.root->data);
scanf("%*s");
return 0;
}
When you are passing your pointer into the function, you create a local version of the pointer. This local variable (node) does indeed point into the same memory that the outer pointer you were passing. However, any attempt to change this variable (not the memory it points to, but the pointer variable itself) will only change the local variable.
So your node points to the same memory location as your tree, but the node variable itself isn't equal to the tree variable, so your changes are not visible from the outer function.
It sounds complicated, sorry, but it's exacly the same thing as in this:
void foo( int a )
{
a++;
}
int main()
{
int var = 5;
foo( var );
std::cout << var;
}
Of course in this case the var will not change, it's the a that is being changed inside the function.
To fix the issue, pass a reference to the pointer instead of the pointer itself:
void addToNode(Node*& node, int value)
In the function addToNode when you assign to node, that assignment is not visible in the function calling addToNode because node is a local variable.
You should pass it as a reference instead:
void addToNode(Node*& node, int value)
{
...
}
Joachim already beat me to the answer, but I'll add this observation in anyway.
Your code leaks memory.
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
Every call to addToNode creates a new Node instance in tmp, but if the parameter Node* node is not NULL, this new Node is not deleted and does not become accessible by the rest of the application.
There are a number of ways to avoid this. The simplest would be to check if node is NULL before creating a new instance.