I am trying to delete the leaf nodes in a BST which I have created non-recursively. The problem is when I am trying to delete the leaf node I hit a segmentation fault and I have no clue as to why its happening. I believe the code which I have commented is causing the problem. Is the idea of deleting that node wrong or are there any other ways of deleting any node from the BST ?
#include <stdio.h>
#include <stdlib.h>
struct BSTnode
{
int data;
struct BSTnode *left,*right,*parent;
};
typedef struct BSTnode node;
void insert(node **root,int val)
{
node *ptr,*newptr;
newptr=(node *)malloc(sizeof(node));
newptr->left=NULL;
newptr->right=NULL;
newptr->parent=NULL;
newptr->data=val;
if((*root)==NULL)
{
(*root)=newptr;
return;
}
ptr=(*root);
while(ptr!=NULL && ptr->data!=val)
{
if(ptr->data >val )
{
if(ptr->left!=NULL)
ptr=ptr->left;
else
{
ptr->left=newptr;
newptr->parent=ptr;
break;
}
}
else
{
if(ptr->right!=NULL)
ptr=ptr->right;
else
{
ptr->right=newptr;
newptr->parent=ptr;
break;
}
}
}
}
void deleteLeaf(node **root)
{
node *leafParent=NULL;
if((*root)->left!=NULL)
deleteLeaf(&((*root)->left));
if((*root)->right!=NULL)
deleteLeaf(&((*root)->right));
if((*root)->left==NULL && (*root)->right==NULL)
{
/* leafParent=(*root)->parent;
if(leafParent->left==(*root))
leafParent->left=NULL;
else
leafParent->right=NULL;
*/
free(*root);
}
}
void inorder(node *root)
{
if(root->left!=NULL)
inorder(root->left);
printf(" %d ", root->data);
if(root->right!=NULL)
inorder(root->right);
}
main()
{
node *root=NULL;
int i,n,val;
printf("\n How many elements ?");
scanf("%d",&n);
for(i=0;i<n;++i)
{
scanf("%d",&val);
insert(&root,val);
}
printf("\n Inorder traversal : ");
inorder(root);
deleteLeaf(&root);
printf("\n Inorder traversal : ");
inorder(root);
}
Indeed there are cases in the function deleteLeaf where the (commented out) leafParent is NULL, and then as soon as you dereference it with leafParent->left, it seg faults. So you need to put a check in there as follows:
leafParent=(*root)->parent;
if (leafParent)
{
if(leafParent->left==(*root))
{
leafParent->left=NULL;
}
else
{
leafParent->right=NULL;
}
}
This will prevent the seg fault, but I am not clear if the function will end up doing what you want it to do... In other words your logic might still need some tweaking to get it to just delete the leaf nodes (if that is what you are attempting to do).
I believe you are not really deleting just the leaves - you are recursively deleting the whole tree: for each node you first you delete the leaves and then check whether it is a leaf ((left == NULL) && (right == NULL)) - which it obviously is since you just deleted its descendants - and then delete it.
The first problem is, as Chris quickly pointed out, that you are not checking that leafParent can become NULL. Either check for that or set parent to itself for the root node so that you don't dereference NULL. The other (imho worse) problem is that you are not invalidating pointers once you free the memory - good habit is to set pointers to NULL as soon as you free them. If you don't do checks later on you can segfault but won't silently corrupt memory by using the pointer later on when the chunk of memory might be allocated by some other structure. You can even write a wrapper to do that for you (and it can also check for attempts to free a NULL pointer, which is actually a valid operation that just silently does nothing - at least on some platforms). In this particular case, once you finish deleting the whole tree (as that is what really happens), you still have pointer to the removed root node inside of main() - and you use it immediately.
As a nitpicking side-note, in code it is either int main(void) { ... } or int main(int argc, int **argv) { ... } not just main(). :-)
Related
I have written this code for strict Binary Search trees. (If every non-leaf node in a binary tree has nonempty left and right subtrees, the tree is termed a strictly binary tree. Or, to put it another way, all of the nodes in a strictly binary tree are of degree zero or two, never degree one. A strictly binary tree with N leaves always contains 2N – 1 nodes.) Unfortunately, it's not printing values correctly. I don't know what's the problem. I have seen other sites on the internet and the code is nearly same but still, I can't find a bug in my code.
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node* prev;
int data;
struct node* next;
};
void Binary_Search_Tree(struct node *newnode,struct node *p);
void print(struct node* p);
main()
{
struct node *root,*nnode,*temp;
int c,d;
root=malloc(sizeof(struct node));
printf("Enter the root data\t");
scanf("%d",&d);
root->data=d;
root->prev=NULL;
root->next=NULL;
while(1)
{
printf("Enter your choice\n1 insert element.\n2 print tree.\n3 Exit");
scanf("%d",&c);
switch(c)
{
case 1:
nnode=malloc(sizeof(struct node));
printf("Enter the node data\t");
scanf("%d",&d);
nnode->data=d;
nnode->prev=NULL;
nnode->next=NULL;
temp=root;
Binary_Search_Tree(nnode,temp);
break;
case 2:
temp=root;
print(temp);
break;
case 3:
free(root);
free(nnode);
free(temp);
temp=nnode=root=NULL;
exit(1);
break;
}
}
return 0;
}
void Binary_Search_Tree(struct node *newnode,struct node *p)
{
if(newnode->data<p->data)
{
if(p->prev=NULL)
{
p->prev=newnode;
}
else if(p->prev!=NULL)
{
p=p->prev;
Binary_Search_Tree(newnode,p);
}
}
else if(newnode->data>p->data)
{
if(p->next=NULL)
{
p->next=newnode;
}
else if(p->next!=NULL)
{
p=p->next;
Binary_Search_Tree(newnode,p);
}
}
}
void print(struct node* p)
{
if(p!=NULL)
{
print(p->prev);
printf("%d\n",p->data);
print(p->next);
}
}
The major problem is you have used assignment in place of equality.
if( p->next=NULL )
does completely differently than what you expected it to be. It would be
if ( p->next == NULL )
^^^
Same for the p->prev the check would be p->prev == NULL.
So let's analyze the first case where you made the error.
if( p->next = NULL )
first assigns NULL to the p->next and then we know the result of assignment statement is the value assigned. So the conditional would be
if( NULL )
So the if statement is never entered. So is else because then p->next = NULL. So it doesn't add the new node. Tree remains unchanged.
It didn't stop here. As you lost the address of the newly allocated node - you have memory leak here.
Then comes the solution
if( p->next == NULL )
Well when we reach a leaf level it would be equal to NULL and then you assign to it the address of newly allocated node. That solves the problem.
Few things -
Check the return value of malloc. In case it fails it would return NULL. 1
root=malloc(sizeof(struct node));
if( root == NULL ){
perror("Malloc failure");
exit(EXIT_FAILURE);
}
Free the dynamically allocated memory when you are done working with it.
void freeTree(struct node *root){
if( root ){
freeTree(root->prev);
freeTree(root->next);
free(root);
}
}
Enable compiler warnings -Wall -Werror. If you did that compiler would have clearly shown you the problem.
error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
if(p->next=NULL)
^~
Well another thing check the return value of scanf.
if( scanf("%d",&d) != 1 ){
// Input failed
exit(EXIT_FAILURE); // or handle error.
}
As mentioned in comment by Jonathan Leffler, readablility will improve if you write the statement properly spaced. else if(newnode->data>p->data) is hard to read. Compared to that else if (newnode->data > p->data) is much more readable. The error would be readily visible to your eye when you write the statement if(p->next = NULL). The obvious one would be if(p->next == NULL).
Freeing the tree is a bit tricky in that you will have to always perform post order traversal. You need to free the children first then you would go for freeing the parent. Otherwise there will be memory leak.
1. Earlier I mentioned fprintf(stderr,...) Basile Starynkevitch to use perror which is a good choice for printing diagnostic error messages.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I need to create a c program for BST but I can't create left child or right child for the root node. Creation of root node is ok. I can also search the element in the root node. But Can't add more than one element in the tree
Please help me solve this problem, kindly explain about the mistake that I made
#include<stdio.h>
#include<stdlib.h>
typedef struct tree
{
struct tree *left;
int data;
struct tree *right;
}node;
node *ROOT;
//////////////////////////
void *bud()
{
return (node *)malloc(sizeof(node));
}
/////////////////////
void createNode(int data, node *ptr)
{
if(ptr==NULL)
{
ptr=bud();
ptr->data=data;
ptr->left=NULL;
ptr->right=NULL;
ROOT=ptr;
ptr=NULL;
printf("DONE");
return;
}
else if(data==ptr->data)
{
printf("Duplication not possible");
return;
}
else if (data<ptr->data)
{
//ptr=ptr->left;
createNode(data,ptr->left);
}
else if (data>ptr->data)
{
//ptr=ptr->right;
createNode(data,ptr->right);
}
else
{
printf("INVALID");
}
}
//////////////////////////////////////
void search(int data,node *ptr)
{
if(ptr==NULL)
{
printf("NOT FOUND");
return;
}
else if (ptr->data==data)
{
printf("Item Found");
return;
}
else if(data<ptr->data)
{
//ptr=ptr->left;
search(data,ptr->left);
}
else if (data>ptr->data)
{
//ptr=ptr->right;
search(data,ptr->right);
}
else
{
printf("INVALID");
}
}
/////////////////////////////////
void main()
{
int ch;
ch=0;
while (ch!=6)
{
printf("\nMENU\n1. Create Tree\n2. Search\n3. Inorder\n4.
Preorder\n5. Postorder\n6. Exit\n EnterYour Choice: ");
scanf("%d",&ch);
if(ch==1)
{
int dat;
printf("\nEnter the number to be inserted: ");
scanf("%d",&dat);
createNode(dat,ROOT);
}
else if(ch==2)
{
int dat;
printf("Enter number to be searched: ");
scanf("%d",&dat);
search(dat,ROOT);
}
else if(ch==6)
{
return;
}
else
{
printf("\nEnter a valid choice\n");
}
}
}
The problem is logical error. I can't create the left or right child of the tree. Whatever I insert to the tree gets inserted to the root node.
I can't create the left or right child of the tree. Whatever I insert to the tree gets inserted to the root node.
This is happening because of this statement in your createNode():
ROOT=ptr;
Whenever you are inserting an element in the tree, you are traversing tree recursively and when you find the appropriate location to insert, you are passing it to createNode() which is NULL (either ptr->left or ptr->right) and ROOT is reassigned to ptr.
If I just make changes in your program to make work it properly, the createNode() will look like this:
void createNode(int data, node **ptr)
{
if(*ptr==NULL)
{
*ptr=bud();
(*ptr)->data=data;
(*ptr)->left=NULL;
(*ptr)->right=NULL;
printf("DONE");
return;
}
else if(data==(*ptr)->data)
{
printf("Duplication not possible");
return;
}
else if (data<(*ptr)->data)
{
createNode(data,&((*ptr)->left));
}
else if (data>(*ptr)->data)
{
createNode(data,&((*ptr)->right));
}
else
{
printf("INVALID");
}
}
And in main(), you need to do:
createNode(dat,&ROOT);
However, there is a scope of improvement in your program, for e.g. separate the node creation and insertion operation in your program. I am leaving it up to you to find the improvements and better ways of theirs implementation.
The error is in your createNode() function: you pass node *ptr and assign like this ptr=bud();. But this only modifies local variable, not pointer in parent node. Try passing node **ptr and do dereferencing inside of the function *ptr=bud();. Use & operator to derive pointer to pointer. As #H.S. mentioned ROOT=ptr; statement makes your program lose node. Besides you allocate memory and don't free it (you can't even do that, because you lose pointer to ROOT node).
Repeated Question:
Recently I'm reading Data Structure(Binary Search Trees), I understand recursion very well and can trace it as well.
I used an approach which always worked for me i.e write a program with a loop, then eliminate loop and write a recursive function, the base condition will be same as loop exit condition.
But when it comes to writing one without my loop method, am getting failed.
I wasn't able to write a recursive function to insert a node in Binary Search Tree.(Though I understood it properly by referring the solution).
Kindly guide me, How to improve it?
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left;//To store the address of the left child
struct node *right;//To store the address of the Right child
};
struct node * root;
struct node *createnewnode(int x)
{
struct node *n=(struct node *)malloc(sizeof(struct node));
n->data=x;
n->left=NULL;
n->right=NULL;
return n;
}
void Insert(int x)
{
struct node *a,*b;
struct node *temp=root;
if(root==NULL)
root=createnewnode(x);
else
{
while(1)
{
if(x<=temp->data)
{
if(temp->left!=NULL)
temp=temp->left;
else
{
a=createnewnode(x);
temp->left=a;
break;
}
}
else
{
if(temp->right!=NULL)
temp=temp->right;
else
{
a=createnewnode(x);
temp->right=a;
break;
}
}
}
}
}
int main()
{
root==NULL;//Empty Tree
Insert(15);
Insert(10);
Insert(20);
Insert(25);
return 0;
}
Edit: Sorry for not posting the code previously.
This is the code I have written for inserting a node, now how do I convert this into a recursive method?
The recursive Insert always asks the following question: can I insert a node in the current root? If not because root is not null then I have to check whether I have to recurse on the left or right subtree and call Insert recursively.
Something like the following should be enough to give you an idea on how to do it
Node* Insert(Node* root, int x) {
if (root == NULL)
return createnewnode(x);
else
if (x <= root->data)
root->left=Insert(root->left);
else
root->right=Insert(root->right);
}
In the below code, I'am creating a binary tree using insert function and trying to display the inserted elements using inorder function which follows the logic of In-order traversal.When I run it, numbers are getting inserted but when I try the inorder function( input 3), the program continues for next input without displaying anything. I guess there might be a logical error.Please help me clear it.
Thanks in advance...
#include<stdio.h>
#include<stdlib.h>
int i;
typedef struct ll
{
int data;
struct ll *left;
struct ll *right;
} node;
node *root1=NULL; // the root node
void insert(node *root,int n)
{
if(root==NULL) //for the first(root) node
{
root=(node *)malloc(sizeof(node));
root->data=n;
root->right=NULL;
root->left=NULL;
}
else
{
if(n<(root->data))
{
root->left=(node *)malloc(sizeof(node));
insert(root->left,n);
}
else if(n>(root->data))
{
root->right=(node *)malloc(sizeof(node));
insert(root->right,n);
}
else
{
root->data=n;
}
}
}
void inorder(node *root)
{
if(root!=NULL)
{
inorder(root->left);
printf("%d ",root->data);
inorder(root->right);
}
}
main()
{
int n,choice=1;
while(choice!=0)
{
printf("Enter choice--- 1 for insert, 3 for inorder and 0 for exit\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("Enter number to be inserted\n");
scanf("%d",&n);
insert(root1,n);
break;
case 3:
inorder(root1);
break;
default:
break;
}
}
}
Your insert accepts a pointer to a node, which is local to the scope of the function. After insert returns, the root it was called upon remains unchanged. And you get a leak.
If you want the changes insert does to be visible outside of it, start by changing its signature
void insert(node **root,int n)
And calling it like so:
void insert(&root1, n);
That way, it will modify root1 and not a copy of it.
As a rule of thumb, if a function needs to modify something, it should be passed a pointer to it. You function needs to modify a node*, so it should be passed a node**.
EDIT
As unwind pointed out, you could also return the root as a means of updating it
root1 = insert(root1, n);
This of course works only if you need to modify one object.
Your allocation code is off, root1 will always stay NULL since the malloc result is only assigned to a local variable. Pass root in as a pointer to pointer.
Additionally you unconditionally malloc left and right, even though there might already be data there, you should call insert immediately and have the called insert handle the malloc just like for root. Again with a pointer to pointer of course.
Finally you else root->data = n doesn't make any sense, it's already n. And I presume you don't want duplicates in your tree? If you do you need to change your code.
Pass reference of node * to the insert() so that when new node is allocated, its appropriately updated.
Also, in your insert() function, don't allocate while moving into below tree. If you allocate then your code tries to check the value on that node and proceed again, which is not correct.
Updated code would be:
void insert(node **root_ptr,int n)
{
if(root==NULL) //for the first(root) node
{
root=(node *)malloc(sizeof(node));
root->data=n;
root->right=NULL;
root->left=NULL;
*root_ptr = root;
}
else
{
if(n<(root->data))
{
//root->left=(node *)malloc(sizeof(node));
insert(&root->left,n);
}
else if(n>(root->data))
{
//root->right=(node *)malloc(sizeof(node));
insert(&root->right,n);
}
else
{
root->data=n;
}
}
}
From main() call it as insert(&root1,n);
#include<stdio.h>
#include<stdlib.h>
//double linked list
struct node {
int data;
struct node *rnext;
struct node *lnext;
}*first=NULL,*last=NULL;
//double linked list
void insertion() {
struct node *nn=malloc(sizeof(*nn));
printf("enter data to be inserted\n");
scanf("%d",&nn->data);
nn->rnext=NULL;
nn->lnext=last;
if(first == NULL) {
first = nn;
last = nn;
}
else{
last->rnext=nn;
}
last=nn;
}
void display() {
struct node *temp;
if(first==NULL) {
printf("list is empty\n");
return;
}
temp=first;
while(temp!=NULL) {
printf("%d \n",temp->data);
temp=temp->rnext;
}
}
void deletion() {
struct node *temp;
if(first==NULL) {
printf("list is empty\n");
return;
}
temp=first;
first=first->rnext;
first->lnext=NULL;
free(temp);
}
int main() {
int option;
do {
printf("enter option 1.insert\n 2.display\n 3.delete\n 4.exit\n");
scanf("%d",&option);
switch(option) {
case 1:
insertion();
break;
case 2:
display();
break;
case 3:
deletion();
break;
}
} while(option!=4);
}
This is a program written for deleting and inserting a node in double linked list. The program compiles without error, but it fails at run-time with a segmentation fault error while deleting a node when there is only one node in the list. Can anyone please help with the solution for this segmentation fault?
Here is some sample output from the program:
./out
enter option 1.insertion
2.display
3.deletion
4.exit
1
enter data to be inserted
11
enter option 1.insertion
2.display
3.deletion
4.exit
2
11
enter option 1.insertion
2.display
3.deletion
4.exit
3
Segmentation fault
The absolute easiest way to solve this one is run it in a debugger. You probably won't even need to learn how to step through your code or anything - just fire up, run, and read the line.
If you are on a *nix as your tag indicated:
Compile your code with -g flag.
Load as, e.g. gdb a.out.
Run now that it's loaded - (gdb) run.
Do whatever you need to reproduce the segfault.
bt or where should give you a stack trace - and an exact line that is causing your problem.
I'm sure enough you can solve it from there to post this as an answer; but if not, knowing the exact line will make it very much easier to research and solve.
At least two bugs:
On one hand, in the insertion function, the memory allocation is incorrect:
struct node *nn=malloc(sizeof(*nn));
It should be :
struct node *nn= (struct node *) malloc(sizeof(struct node));
On the other hand, in the deletion function. If there is only one node. After the statement
first=first->rnext;
the pointer first become NULL. Then you try to use it as:
first->lnext=NULL; // first is NULL
Then segment fails.
temp=first;
first=first->rnext;//when only one, first is NULL(first->rnext)
first->lnext=NULL;//(NULL)->lnext , Segmentation fault!!
free(temp);
maybe fix to
temp=first;
if(first == last){//if only one
first = last = NULL;
} else {
first=first->rnext;
first->lnext=NULL;
}
free(temp);