Deletion in BST - c

I was trying to perform deletion in a binary search tree (BST), but it was giving a segmentation fault after printing the deleted array.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
minVal(root->left);
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(value>root->value)
deleteBST(root->right,value);
else if(value<root->value)
deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
}
}
return root;
}

Presumably the point of deleteBST() returning a treeNode * is that the return value points to the new root of the (sub)tree. The new root will differ from the original one if the deleted value was found in the original root, so some means of updating the root is required.
That needs to be handled appropriately by this function's callers, including this function itself when it performs recursive calls. Your function fails to do this.
Your function also fails to properly handle the case when the specified value is not found in the tree. It will eventually attempt to dereference a null pointer if such a value is passed.
And the actual deletion performed by your function is totally inadequate. It frees the node where the value is found, but it does not adjust the subtree rooted at that node to have a valid structure, and it leaves the parent of the deleted node with a (then) invalid child pointer.
The general scheme for deletion from a BST would be like this:
if the root, R, of the tree is null then return null; otherwise,
if the value to delete is less than the value of R, then
delete it from the left subtree and update R's left pointer to point to the new root of the left subtree; otherwise,
if the value to delete is greater than the value of R, then
delete it from the right subtree and update R's right pointer to point to the new root of the right subtree; otherwise,
the value to delete is the value of R itself. In this case,
Select a new root for this subtree:
if both R's children are null then the new root is also null.
if exactly one child is null then the other is the new root.
if neither child is null then you can choose either the smallest node in the right subtree or the largest one in the left subtree. These are R's immediate in-order successor and predecessor, respectively.
In the case where neither of R's children is null, update the subtree appropriately. Supposing that the smallest node of the right subtree, MR, is the selected new root, you must
remove MR from its current parent by updating the parent's pointer to it to point instead at MR's right child (which might or might not be null). Including when the parent is R.
update MR's left and right child pointers to be the same as R's.
Free R.
return the root of the subtree (original or new, as appropriate)

updated working code is attached with comments to the errors.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
return minVal(root->left);//1.returning a value is a must here
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(root==NULL)//2.handling the base case
return NULL;
if(value>root->value)
return deleteBST(root->right,value);
else if(value<root->value)
return deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
return root;//can be skipped
}
}
return root;
}

Related

Deleting a node in a bst in c

void MorrisTraversal(tNode* root)
{
tNode *current, *pre;
if (root == NULL)
return;
current = root;
while (current != NULL)
if (current->left == NULL) {
current = current->right;
}
else {
pre = current->left;
while (pre->right != NULL
&& pre->right != current)
pre = pre->right;
if (pre->right == NULL) {
pre->right = current;
current = current->left;
}
else {
pre->right = NULL;
current = current->right;
}
}
}
}
I use this function to travers the bst, i also have a function (delete) that takes a node as parameter and delets it from the tree.
I'd like for example to remove from the tree all nodes whose value is 4, is it possible to do so using the functions mentioned above?
Like traversing the tree one time and removing all the nodes with a certain property.
I hope my problem it's clear...
Thanks in advance!
It is possible, but you will need to modify your Traversal function.
Currently MorrisTraversal traverses the tree, but it doesn't do anything to any node. You could modify MorrisTraversal to call a function on the current node (probably on the line after while (current != NULL).
I would first try putting a simple print function/line there that prints the value of the current node and run it to verify your tree traversal works as expected.
Then you could change the print function to modify the node in some way.
If you do delete the node, you will have to be careful to clean up the tree. Eg. if you have the following tree Where A is the root node:
A-B-C
|
D-E
|
F
What happens if you delete B? Will you move C, A. or D into B's place?
Good luck!

deleting binary search tree

I am trying to delete the whole binary search tree ( every node in the tree), which one of these functions do you think will work better?
private:
struct Node {
string value;
Node* left;
Node* right;
};
Node* root;
public:
BST() {
root = NULL;
}
~BST() {
delete root->left;
delete root->right;
}
or:
...
void destroyTree (Node*& tree) {
while (tree != NULL) {
tree = tree->left;
delete tree;
}
while (tree != NULL) {
tree = tree->right;
delete tree;
}
delete tree;
}
Neither the proposed destructor ~BST() nor the proposed function destroyTree()of the class BST will delete the BST instance and will be better than the other.
Explanation 1 - what the destructor ~BST() is doing ?
The proposed source is simple delete root->left; followed by delete
root->right; and will delete only 2 nodes of the BinarySearchTree.
The node root is not check with NULL and otherwise is never deleted,
The node root->left is not check with NULL too,
The node root->right is not check with NULL too,
Explanation 2 - what the function destroyTree() is doing ?
Two while-loops to try the exploration of the tree, one for the left
branch and one for the right branch. The condition (tree != NULL) is
present only to exit from the loop but doesn't check if the current
node could be deleted.
With the left loop, only ->left nodes of the root->left will be deleted until tree->left == NULL and CRASH when trying to delete tree;,
Even after adding a if (tree==NULL) break; to exit from the loop before calling the delete tree; a new CRASH in the right loop,
And the last delete tree; is a non-sense because at this position, tree is always '== NULL`.
Bonus Solution - based to a modification of the function destroyTree().
A recursive function will be the simplest way to delete all created
and inserted nodes. But be aware with the size of the BinarySearchTree
and especially the deepest branch.
void destroyTree(Node *cur_node) {
if (cur_node!=NULL) {
// explore and delete on left
destroyTree(cur_node->left); // recursive-call
// explore and delete on right
destroyTree(cur_node->right); // recursive-call
// delete each node
delete cur_node;
}
}

Unable to print elements in binary search tree

My code is not printing the elements of binary search tree:
//x is the element to be inserted
//structure of program
typedef struct BST
{
int info;
struct BST *left;
//pointer to left node
struct BST *right;
//pointer to right node
}
bst;
//global root variable
bst *root;
void insert(int x)
{
bst *ptr,*sptr=root;
ptr=(bst*)malloc(sizeof(bst));
ptr->info=x;
if(root==NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr;
}
edit:
//following is the show function
void show()
{
bst *ptr=root;
while(ptr!=NULL)
{
//it will print untill the ptr is null
printf("%d",ptr->info);
ptr=ptr->left;
ptr=ptr->right;
}
}
Where is the value of root coming from? You're not passing in the value anywhere? Also, it is tough to help when we don't know the design of type bst.
It appears that you have the right idea. Create a node, and give it some data. If the root is null, then the new value is the root of the BST. After that you go ahead and find the first null node either in the left or right subtree of the root using the standard BST behavior. Finally, when you reach the end you go ahead and insert the last node in the proper place.
void insert(int x)
{
bst *ptr, *sptr=root; //<-- the value right here?
ptr = malloc(sizeof(bst));
ptr->info = x;
if(root == NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr; // <-- What is this line trying to do?
}
However, where did your updated tree go?
Since in C everything is passed by value, you're running into the problem where you're not seeing your updated tree after you leave this function. You need to go ahead and change the function to return a bst* type, and also maintain the root node during the entire function. Now the first line of code (*sptr = root) makes more sense! Finally, you were not setting the left and right fields of ptr to NULL. This means you were jumping over your if statements.
bst* insert(int x, bst *root)
{
bst *ptr, *sptr=root;
ptr = malloc(sizeof(bst));
ptr->left = NULL;
ptr->right = NULL;
ptr->info = x;
if(root == NULL)
{
ptr->left=ptr->right=NULL;
root=ptr;
return root;
}
while(sptr!=NULL)
{
if(x<sptr->info)
{
sptr=sptr->left;
}
else
sptr=sptr->right;
}
sptr=ptr;
return root;
}
What about the next function?
I just started looking at this one too. I am not used to the global variables in c, so I will go ahead and make two modifications. Let's make this recursive, and pass in the value of the root rather than using the global.
void show(bst *root)
{
if(root == NULL){
return;
}
printf("%d",root->info);
show(root->left);
show(root->right);
}
This will take in some value, and solve the tree recursively, and print as it reaches each node. Thus, it will print the root node (if it exists), and then print the left entire left subtree before it prints the right subtree.
Finally, looking at your main
I added the local variable root and thus you will have to remove the global variable named root outside of your main function. I also set the value of it to null so your first insert will fire correctly.
int main()
{
int i,n,x;
bst *root = NULL; //<-- I added this line of code to remove the global
puts("Enter number of elements");
scanf("%d",&x);
for(i=0;i<x;i++)
{
puts("Enter elements");
scanf("%d",&n);
root = insert(n, root);
}
show(root);
return 0;
}
I hope this helps!

Problem with pointers in binary search tree deletion

I am trying to implement binary search tree operations and got stuck at deletion.
11
/ \
10 14
Using inorder traversal as representation of tree initially output is 10 11 14.
Deleting node 10, output expected is 11 14 but I am getting 0 11 14.
Deleting node 14, output expected is just 11 but I am getting 0 11 67837.
Please explain why I am getting wrong output. I am not looking for any code :).
typedef struct _node{
int data;
struct _node *left;
struct _node *right;
} Node;
Node* bstree_search(Node *root, int key)
{
if(root == NULL){
return root;
}
// Based on binary search relation, key can be found in either left,
// right, or root.
if(key > root->data)
return bstree_search(root->right, key);
else if(key < root->data)
return bstree_search(root->left, key);
else
return root;
}
void bstree_insert(Node **adroot, int value)
{
// since address of address(root is itself address) is passed we can change root.
if(*adroot == NULL){
*adroot = malloc(sizeof(**adroot));
(*adroot)->data = value;
(*adroot)->right = (*adroot)->left = NULL;
return;
}
if(value > (*adroot)->data)
bstree_insert(&(*adroot)->right, value);
else
bstree_insert(&(*adroot)->left, value);
}
void bstree_inorder_walk(Node *root)
{
if(root != NULL){
bstree_inorder_walk(root->left);
printf("%d ",root->data);
bstree_inorder_walk(root->right);
}
}
void bstree_delete(Node **adnode)
{
//Node with no children or only one child
Node *node, *temp;
node = temp = *adnode;
if((*adnode)->right == NULL || (*adnode)->left == NULL){
if((*adnode)->right == NULL){
*adnode = (*adnode)->left;
}else{
*adnode = (*adnode)->right;
}
}else{ // Node with two children
}
free(temp);
}
int main()
{
Node *root = NULL;
Node *needle = NULL;
int i,elems[] = {11,10,14};
for(i = 0; i < 3; ++i)
bstree_insert(&root,elems[i]);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 10);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 14);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
}
Please explain why I am getting wrong
output.
Your delete function must also change the parent of the deleted Node. For example, when you delete the node holding 10, you must set the root Node's left child to NULL. Since you don't do this, when you later traverse the tree, you print out data that has already been freed.
I did not look at any code other than delete, so I can't make any guarantees about it working once this change is made.
You're getting wrong output because your deletion code is buggy (okay, maybe that's stating the obvious).
To delete from a binary search tree, you first find the node to be deleted. If it's a leaf node, you set the pointer to it in its parent node to NULL, and free the node. If it's not a leaf node, you take one of two leaf nodes (either the left-most child in the right sub-tree, or the right-most child in the left sub-tree) and insert that in place of the node you need to delete, set the pointer to that node in its previous parent to NULL, and delete the node you've now "spliced out" of the tree.
A couple of things really quick,
first when you allocate the node, you really should be doing the malloc on the sizeof the type (ie Node).
Second, if you have 2 children it looks like you are not really deleting the node and rebuilding the search tree by promoting one of the children.
Other people have already got you other obvious errors.

Binary Trees in C

I'm trying to insert nodes into a tree in order. My function works fine... when there's only three nodes.
I have this code:
typedef struct _Tnode Tnode;
struct _Tnode {
char* data;
Tnode* left;
Tnode* right;
};
Along with this:
Tnode* add_tnode(Tnode* current_node, char* value) {
Tnode* ret_value;
if(current_node == NULL) {
current_node = (Tnode*) malloc(sizeof(Tnode));
if(current_node != NULL) {
(current_node)->data = value;
(current_node)->left = NULL;
(current_node)->right = NULL;
ret_value = current_node; }
else
printf("no memory");
}
else {
if(strcmp(current_node->data,value)) { //left for less than
ret_value = add_tnode((current_node->left), value);
current_node -> left = (Tnode*) malloc(sizeof(Tnode));
(current_node -> left) -> data = value;
}
else if(strcmp(current_node->data,value) > 0) {
ret_value = add_tnode((current_node -> right), value);
current_node -> right = (Tnode*) malloc(sizeof(Tnode));
(current_node -> right) -> data = value;
}
else {
printf("duplicate\n");
ret_value = current_node;
}
}
return ret_value;
}
I know what's wrong here, I just don't know how to fix it. This just overwrites the two nodes attached to the root node. i.e.
|root_node|
/ \
|node_2| |node_3|
I can't add a node four. It just overwrites node 2 or 3 depending on the input. After debugging and a little research, I'm not quite sure where to go from here...
If anyone can help, I'd really appreciate it.
You should leave the mallocing only to the case where the insertion reaches a leaf node (ie NULL). In the other cases, all you should do is to traverse to the next level depending on your comparison. In your case, you're traversing to the next level, and then killing it with a new malloc. Because of this you're never getting past the first level.
eg.
if (current_node == NULL) // Do initialization stuff and return current_node
if (strcmp(current_node->data, value) < 0) {
current_node->left = add_tnode((current_node->left), value);
} else if (strcmp(current_node->data, value) > 0) {
current_node->right = add_tnode((current_node->right), value);
}
return current_node;
This would appear to just be a school project.
Where to begin.
1) You are clobbering left/right all the way down the tree. I'm not sure why you would expect them to be preserved since:
a) You always write to these nodes.
b) The only time you return an existing node is on a strcmp match.
2) You really need to check strcmp < 0 on your first compare.
3) For a non-balanced tree, there's no reason to use recursion - you can just use a loop until you get to a leaf and then hook the leaf. If you really want recursion...
4) Recursive... Return NULL in all cases except when you create a node (ie: the first part where you have current == NULL).
5) In the left/right, store the return value in a temp local Node*. Only if the return value is not NULL should you assign left/right.
Even this doesn't feel right to me, but if I started from scratch it just wouldn't look like this at all. :) We won't even get into the memory leaks/crashes you probably will end up with by just pushing 'char *' values around all willy nilly.
struct _Tnode {
char* data;
struct _Tnode * left, * right;
};
typedef struct _Tnode Tnode;
void addNode(Tnode ** tree, Tnode * node){
if(!(*tree)){
*tree = node;
return;
}
if(node->data < (*tree)->val){
insert(&(*tree)->left, node);
}else if(node->data>(*tree)->data){
insert(&(*tree)->right, node);
}
}
for starters - the first strcmp
if(strcmp(current_node->data,value))
is probably not right - this is true for both less than and greater than, and then the second if does not make sense
I guess that you'll need to add a pointer to the parent node to the _Tnode struct.
The problem is that after making your recursive function call to add_tnode, on the left branch, say, you are obliterating that same branch with your malloc. The malloc should only happen when you have recursed down to the point where you will be adding the node, not when you are making a recursive call.
Essentially, in a particular function call, you should either make a recursive call OR malloc a new node, not both.
This also produces a memory leak, probably.
If you aren't implementing this for your own edification, I would just use libavl
You don't need to know the parent of the node. just the value at the current node.
Pseudocode:
add_treenode(root, value)
{
//check if we are at a leaf
if root == null
allocate space for new node.
set children to null
save root->value = value
return root // if you need to return something, return the node you inserted.
//if not, this node has a value
if root->value < value //use strcmp since value is a string
add_tnode(root->left, value)
else
add_tnode(root->right, value)
return NULL
}
This is as clean as it gets when it comes to inserting a new tree node. pass the root and the value of the node you want to insert, and it does the rest.
Once you found out, that current_node->data is not null and compared it with value, you first have to check whether the corresponding pointer current_node->left (or ->right) is already in use (!= NULL).
If it is null, you proceed as you do. That is the case that works fine now.
If not, you have to retest the whole thing against the correspondig node, calling your function again on the cooresponding node. Here some pseudo code:
Wrap the code with:
void Add_node(Tnode* current_node) {
...
else {
if(strcmp(current_node->data,value) < 0) { //left for less than
if(current_node->left != NULL) {
Add_node(current_node->left);
} else {
ret_value = add_tnode((current_node->left), value);
current_node -> left = (Tnode*) malloc(sizeof(Tnode));
(current_node -> left) -> data = value;
} else if(strcmp(current_node->data,value) > 0) {
Add_node(current_node->right);
} else {
...
}
This is called recoursion (a function callin itself) and walk through the tree. To read some node, you have to do a recursive function again. Be carefull that they terminate (here at some point the left or right pointer will be null, thus terminating the recursive calling).

Resources