I'm trying to write a code to insert a new element in the BST iteratively. When I try to execute the code, I get a segfault. Can someone look over the code and help me correct it?
bool insert2(int item)
{
BstNode *parent;
BstNode *root=new BstNode;
cout<<root->data;
cout<<"\n";
BstNode *ptr;
int ctr=0;
//cout<<root->data;
if (root==NULL)
{
BstNode *temp=new BstNode;
temp->data=item;
temp->left=NULL;
temp->right=NULL;
root=temp;
//cout<<root->data;
return true;
}
else
{
ptr=root;
while (ptr!=NULL)
{
ctr=ctr+1;
cout<<ctr;
if (ptr->data==item)
{
cout<<ptr->data;
return false;
}
if (item < ptr->data)
{
parent=ptr;
ptr=ptr->left;
}
else
{
parent=ptr;
ptr=ptr->right;
}
}
BstNode *add=new BstNode;
add->data = item;
add->left= NULL;
add->right= NULL;
return true;
}
}
on editing out the root-> data part, the code would go into the first if block and return true, which makes me guess that my problem lies somewhere in the deceleration.
There are a number of things that you are doing wrong. First of all, as PaulMcKenzie has pointed out, you should not be creating the root at the beginning of the function. If the BST does not start out empty, the root already exists and you do not want to create a new one. Instead, the root should be a public variable (which would only allow you to have one BST), or the function should take a pointer to the root as one of the parameters. It certainly does not make sense that you create the root and then test it to see if it is NULL. Unless you ran out of memory, it would not be NULL right after you created it.
Another problem with your code is that after you find the appropriate location in the BST, you create the new node, but do not attach it to the tree. Instead, you might want to insert the following lines after you initialize add:
if(item < parent->data)
parent->left = add;
else
parent->right = add;
As far as the fact that you get a seg-fault every time you call the function, it is probably because, when you declare root, you do not initialize its right and left pointers to NULL. Therefore, the while loop does not stop when it reaches root->left or root->right. When you try to deference ptr later in the loop, you are deferencing an uninitialized pointer, resulting in a seg-fault.
Related
I keep getting the following error : Segmentation fault (core dumped) . I found out the line of code that is causing the problem ( marked with a comment inside of the program) . Please tell me why this error is happening and how to fix it.
I've tried to dry run my code (on paper ) and see no logical errors (from my understanding).
I have only recently got into coding and stackoverflow please guide me through how I can further improve my question , as well as my code . Thanks !
class tree
{
struct node // Creates a node for a tree
{
int data;
bool rbit,lbit; // rbit/lbit= defines if right/left child of root is present or not
node *left,*right;
};
public:
node *head,*root;
tree() // constructor initializes root and head
{
root=NULL;
head=createnode(10000);
}
node *createnode(int value)
{// Allocates memory for a node then initializes node with given value and returns that node
node *temp=new node ;
temp->data=value;
temp->lbit=0;
temp->rbit=0;
temp->left=NULL;
temp->right=NULL;
return temp;
}
void insert(node *temp,int value) // Creates binary search tree node by node
{
if(root==NULL) // Checking if tree is empty
{
root=createnode(value); //Root now points to new memory location
head->left=root;
head->lbit=1;
root->left=head;//this line gives the segmentation fault (what i thought before correction)
}
}
void inorder(node *root) // Inorder traversal of tree (this function is logically incorrect)
{
if(root==NULL)
return;
inorder(root->left);
cout<<root->data<<"\t";
inorder(root->right);
}
void getdata()//Accepts data , creates a node through insert() , displays result through inorder()
{
int data;
cout<<"Enter data"<<endl;
cin>>data;
insert(root,data);
inorder(root);
}
/*void inorder(node *root) // Working inorder code
{
if(root->lbit==1)
inorder(root->left);
cout<<root->data<<"\t";
if(root->rbit==1)
inorder(root->right);
}*/
};
int main()
{
tree t; // Tree Object
t.getdata(); // Calling getdata
return 0;
}
I think the comments section largely reflects a miscommunication. It's easy to believe that you are experiencing a crash ON that particular line.
This is not actually the case. Instead what you have done is created a loop in your tree which leads to infinite recursion by the inorder function. That causes a stack overflow which segfaults -- this would have been extremely easy to spot if you had just run your program with a debugger (such as gdb) attached.
temp = createnode(value);
if(root == NULL)
{
root = temp;
head->left = root;
head->lbit = 1;
temp->left = head;
}
Look at the loop you have just created:
head->left points to root
root->left == temp->left, which points to head
An inorder traversal will now visit:
root
head
root
head
root
head
...
Since it never gets to the end of the left-branch, the function never outputs anything before overflowing the stack and crashing.
So no, your code is not logically correct. There's a fundamental design flaw in it. You need to rethink what you are storing in your tree and why.
From the code,
root=temp; //Root now points to temp
head->left=root;
head->lbit=1;
temp->left=head;// this line gives the segmentation fault
root is not pointing to temp. temp(pointer) is assigned to root(pointer).
head's left pointer is root, and temp's left is head (which means root's left is head). so in the function "inorder",
void inorder(node *root) // Inorder traversal of tree
{
if(root==NULL) <<<<<<
return;
inorder(root->left);
cout<<root->data<<"\t";
inorder(root->right);
}
the argument node *root (left) is never NULL and the function never return.
There's not enough information on exactly how this should work (what is node.lbit for example).
The question's insert() function will not work. It's passing in a value which is immediately overwritten (among other issues). There's no explanation of what tree.head is for, so it's ignored. The fields node.lbit and node.rbit look to be superfluous flags of node.left != NULL (similarly for right). These are omitted too. The insert() is also not creating the tree properly.
void insert(int value) // Insert a value into the tree (at branch)
{
// Create a new node to insert
struct node *temp = createnode(value);
if (root == NULL) // Checking if tree is empty
{
root = temp; //Root now points to temp
}
else
{
insertAtBranch(root, temp);
}
}
// recursively find the leaf-node at which to insert the new node
void insertAtBranch(node *branch, node *new_node)
{
// to create a BST, less-than go left
if (new_node->value <= branch->value)
{
if (branch->left == NULL)
branch->left = new_node; // There's no left-branch, so it's the node
else
insertAtBranch(branch->left, new_node); // go deeper to find insertion point
}
else // greater-than go right
{
if (branch->right == NULL)
branch->right = new_node;
else
insertAtBranch(branch->right, new_node);
}
}
Imagine how a binary tree works. New nodes are only ever inserted at the edges. So you look at a given node, and decide if this new-node is less or grater than the one you're looking at (unless the tree is empty, of course).
Say the new-node.value is less than the branch-node.value, you want to branch left. Still with the same node, if it doesn't have a left-branch (node.left == NULL), the new node is the left branch. Otherwise you need to travel down the left-branch and check again.
I would have made node a class, and used a constructor to at least set the default properties and value. But that's not a big deal.
I was solving problem of insertion of node in a binary tree. I have the following doubts:
1) If we are inserting a node then we should return a pointer pointing to that node as then only we will be able to access the node, right?
2) Then here why are we returning root? We must return root->left or root->right accordingly, where am I wrong?
struct node* insert(struct node* root, int data)
{
if (root == NULL) //If the tree is empty, return a new,single node
return newNode(data);
else
{
//Otherwise, recur down the tree
if (data <= root->data)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data);
return root;
}
}
3) Is this root which the above code returns the changed one from what it was previously due to recursion?
You misunderstand the return value.
The return value of this insert function is a pointer to the subtree that now has data inserted into it. If the passed in root was null, this is a new 1 node tree; if the passed in root is non-null, the return value is the same root.
This makes the recursion a bit simpler. We simply recurse until we run head-on into nullptr in a branch. Then the recursion stops, and the return value sets the parent's left or right node.
To create a brand new tree you type:
node* new_tree = insert(nullptr, 7);
to insert something into an existing tree you type:
existing_tree = insert(existing_tree, 7);
or equivalently
insert(existing_tree, 7);
so long as existing_tree isn't null.
This "double use" of the function (to both create and modify a tree) can confuse, but it makes the specific recursive use a tad less verbose, and makes the "empty tree is a nullptr" and "always do existing_tree = insert(existing_tree, val);" is a rule that makes the empty tree as the null tree work.
This is, however, a very C way of doing things.
A more c++ way of doing things would be:
std::unique_ptr<node> insert(std::unique_ptr<node> root, int data)
{
if (root == nullptr) //If the tree is empty, return a new,single node
return std::make_unique<node>(data);
else
{
//Otherwise, recur down the tree
if (data <= root->data)
root->left = insert(std::move(root->left), data);
else
root->right = insert(std::move(root->right), data);
return std::move(root);
}
}
where the flow of data into and out of the function is more explicit, and we assume node has a constructor that takes data.
This recursive insert should always return the very root node of the tree. Just because you read return root doesn't mean the original function call has finished executing, it just means the n'th recursion has finished. The recursive calls have all been pushed onto the stack and therefore must all be resolved before the original caller receives the returned value.
You can get back to the inserted node by doing a find for the inserted value.
The function to insert at end of linked list using recursion looks something like this
// Main..
for(int i=0;i<n;i++){
cin>>x;
insert(head,x);
}
void insert(struct node*&h,int x){
if(h==NULL){
h=new node(x);
return;
}
insert(h->next,x);
}
But if I am doing same with iteration it doesn't work the same way,Its making only one node.
void insert(struct node* &h,int x){
if(h==NULL){
h=new node(x);
return;
}
struct node* go=h;
while(go){ //At (go==NULL) it should point to next of last node
go=go->next; // I know it should be go->next!=NULL condition.
}
go=new node(x);//Assigning next of last to new node.
}
I am having serious mental blockage.Can anyone please help why it doesn't work ? What should I do to make it work ?
The problem here is that you loop until go is not null. Okay, once fixed, you loop until go is null,
Then you just overwrite a null pointer by a new. But that doesn't link it to your existing list.
Do that instead:
void insert(struct node* &h,int x)
{
if(h==NULL)
{
h=new node(x);
return;
}
struct node* go=h;
// move until last element
while(go->next)
{
go=go->next;
}
// create a node at the end
go->next=new node(x);//Assigning next of last to new node.
}
At first iteration, go is guaranteed to be non-null (checked by first if condition).
Just check for the first next element to be null, and insert your new node here.
I am trying to write a remove from a binary tree function. I'm kinda lost so I'm trying to handle it case by case, starting with if the value I'm trying to remove is in the root of the BST. To test my function, I am first calling a printcontents() function that prints all the contents of the tree, then I'm calling remove(8) [8 being the value in my root at the moment), and then calling printcontents() again. The way I'm doing it is by trying to replace the root with the "right-most" value in the left side of the tree. When I call printcontents the second time, it prints the new root value correctly, but when it continues printing the contents and reaches the point where that value used to be, it has a random long number "-572......"(although i don't think the number matters) and then my program crashes. I see my root's value is being replaced, but what happens afterwards??
Here's my remove function:
void BinarySearchTree::remove(int value) {
Node* tmp = head;
Node* tmp2 = head;
if (head->data == value && head->left != NULL) {
tmp=tmp->left;
while (tmp->right != NULL) {
tmp=tmp->right;
}
while (tmp2->right->right != NULL) {
tmp2=tmp2->right;
}
if (tmp->left == NULL) {
head->data = tmp->data;
tmp2->right = NULL;
delete tmp;
}
if (tmp->left != NULL) {
head->data = tmp->data;
tmp2->right = tmp->left;
delete tmp;
}
}
It's obviously incomplete, but I'm testing it to only handle the case in which the root is removed and replaced by the right-most value in the left side of the tree (assuming there is a left side, which there is), and I feel like logically it should be working, so perhaps it is when I "delete tmp" that things go wrong. I don't know whether posting my whole program will be necessary, but if so, let me know!
May I suggest that instead of writing out for root, why don't you treat the case as it is dealt with in CLRS : That is two distinct cases.
1. When node to be deleted is a leaf
2. When node to be deleted is non-leaf(in that case replace it with inorder successor/predecessor).
The root deletion obviously falls under the second case. This is just a suggestion.
I created a function to insert data to a BST and it works fine. I used "pass by reference" and the value of "head" is supposed to change after each insertion. However, I found that the "head" is always pointing to the first value that I inserted. Could anyone here explain what causes the "head" to point to the first data I inserted?
void insert(node *&head, int val){
if(head == NULL){
head = newNode(val);
}
else{
if(val <head->data)
insert(head->left,val);
else
insert(head->right,val);
}
}
that is how the function should work, head should never change or you will lose track of the tree root.
as long as you have the head pointing at the root, you have access to the whole tree.
the reason why the value is not changing is, when you are writing insert(head->left,val);
you are not assigning a new value to head, you are just passing the reference to the left child to the next function call.
void insert(node *&head, int val){
if(head == NULL){
head = newNode(val); // when you call insert() with pointer to root
// which is NULL this will create root node
}
then when you add data to the root node (whch is not NULL anymore)
else{ // this will be called and this doesn't create new root node
// but just create nodes at its left or right side
if(val <head->data)
insert(head->left,val);
else
insert(head->right,val);
}
}