deleting binary search tree - c

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;
}
}

Related

Deletion in BST

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;
}

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!

How can i delete multiple nodes of a BST in c?

i have to delete some nodes of this BST
struct node {
char *value;
struct node *p_left;
struct node *p_right;
int usable;
};
the nodes that i have to delete are the ones with usable set to 0.
my question is, is it possible to make a sweep of the tree and delete all the nodes with usable == 0? all the resources i found online are about deleting a node containing a certain key, i tried to apply those but they didn't work
--edit:
the remove node function that i implemented was fine:
struct node* deleteNode(struct node* root, char *key) {
if (root == NULL)
{
return root;}
int cmp_result = strcmp(key, root->value);
if (cmp_result < 0)
root->p_left= deleteNode(root->p_left, key);
else if (cmp_result>0)
root->p_right= deleteNode(root->p_right, key);
else{
if (root->p_left==NULL) {
struct node *temp = root->p_right;
free(root);
return temp;
} else if(root->p_right==NULL){
struct node *temp = root->p_left;
free(root);
return temp;
}
struct node* temp = minValueNode(root->p_right);
strcpy(root->value, temp->value);
root->p_right= deleteNode(root->p_right, temp->value);
}
return root;
}
the problems arose because i called this function while traversing the tree, changing the structure of the tree while i'm using it
void pos2(struct node *head, char exactchar, int n)
{
if( head != NULL ) {
pos2(head->p_left, exactchar, n);
if (head->value[n]!=exactchar){
head = deleteNode(head, head->value);}
pos2(head->p_right, exactchar, n);
}
}
like this function that deletes a node if it has a word without a determined char in a determined position in it
is it possible to make a sweep of the tree and delete all the nodes with usable == 0?
Of course.
all the resources i found online are about deleting a node containing a certain key, i tried to apply those but they didn't work
I have no idea what, specifically, you tried. However, algorithms aimed at deleting the node having a specific key clearly do not solve the problem you have posed. They will use the BST-ness of the tree to efficiently find the specific node to delete, if it is present, and delete just that node.
Since your flag does not have a functional relationship with the keys on which the BST is ordered, you need to traverse the whole tree and delete every node you find that satisfies your criterion for doing so. Operationally, I would probably structure that as a depth-first traversal with post-order deletions (that is, consider whether to delete a given node after processing both its subtrees).

Delete node from a C binary tree without messing it up

I am a beginner working on a C binary tree library.I am wondering on how could I delete a node from a binary tree without messing up the entire thing.Here is how I create the tree:
the structure:
struct Node {
int value;
struct Node *left;
struct Node *right;
};
typedef struct Node TNode;
typedef struct Node *binary_tree;
Creation of the tree:
binary_tree NewBinaryTree(int value_root) {
binary_tree newRoot = malloc(sizeof(TNode));
if (newRoot) {
newRoot->value = value_root;
newRoot->left = NULL;
newRoot->right = NULL;
}
return newRoot;
}
Adding elements to it:
void Insert(binary_tree *tree, int val) {
if (*tree == NULL) {
*tree = (binary_tree)malloc(sizeof(TNode));
(*tree)->value = val;
(*tree)->left = NULL;
(*tree)->right = NULL;
} else {
if (val < (*tree)->value) {
Insert(&(*tree)->left, val);
} else {
Insert(&(*tree)->right, val);
}
}
}
my question is basically how I could for example delete a left node,and then "link" the other nodes(or leaves) that were linked to that left node so the tree doesnt have a NULL leaf? Ex: if leaf 4 had 2 children(left3 and right8),then delete leaf 4, it link children left3 and right8 to the upper node(above leaf4).Its hard to explain im trying to do my best.
thank you
The algorithm for deleting from a BST looks conceptually like this:
You search for the node using its key.
Once you have found the node you check if it has only one child.
if it does, you remove the node and put on its place the child you just found.
if it doesn't, you search for the node with the minimum value key in the right subtree. Once you find it, you replace the key of the node you want to delete with this minimum key and you delete the minimum node in the right subtree.
How this whole concept works and how should it look in C code you can read for example here. My suggestion would be to first see this diagram, which illustrates all the possible scenarios.
Good luck!

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.

Resources