Exception: Deletion of node in Binary Search Tree - c++

I am getting Exception when running the BST Deletion. Below is my code snippet:
Bst::node * Bst::del(node *root, int num)
{
if (root == NULL)
{
return root;
}
else if (num < root->data)
{
root->left = del(root->left, num);
}
else if (num > root->data)
{
root->right = del(root->right, num);
}
else
{
if (root->left == NULL)
{
node * tmp = root;
root = root->right;
delete tmp;
}
else if (root->right == NULL)
{
node * tmp = root;
root = root->left;
delete tmp;
}
else if (root->left == NULL && root->right == NULL)
{
delete root;
root = NULL;
}
else
{
node *tmp = root;
tmp = findMin(root->right);
root->data = tmp->data;
root->right = del(root->right, tmp->data);
}
}
return root;
}
void Bst::del(int num)
{
del(root, num);
}
Everything works fine when I am deleting the other nodes but when I delete the root node itself then the function void Bst::del(int num) gets the garbage value from the function Bst::node * Bst::del(node *root, int num). The error gets resolved when I rewrite my function as
void Bst::del(int num)
{
root = del(root, num);
}
Question 1. Why it works when I delete the middle nodes or any other node except the root node. While debugging I found that even root was getting deleted properly when the function Bst::node * Bst::del(node *root, int num)was executing but when the call returned to the void Bst::del(int num) then the value of root was not getting retained and was garbage.
Question 2: Why the error got fixed when I stored the returned value in variable root?

While deleting a BST node using recursion, you must track the root node, which you're doing correctly as
root->left = // ... and root->right = ...
However when call reaches to caller after unwinding the stack, the root may get modified ( case when you delete the root itself )
This hopefully answers both of your questions

Related

C++ trouble deleting nodes with only one child in BST

I'm having difficulty deleting a node in my binary search tree. The delete function is part of my Node class, and my findMin function is as well. Below is my delete function...
/**********************************************
* Delete
**********************************************/
node* node::Delete(node *root, string stuff)
{
//node *temp;
if (root == NULL) // Searches for value in tree
return NULL;
if (stuff < root->val) // String is in left subtree
root->left = Delete(root->left, stuff);
else if (stuff > root->val) // String is in right subtree
root->right = Delete(root->right, stuff);
else
{ // No children
if ((root->left == NULL) && (root->right == NULL))
{
delete(root);
root = NULL;
}
else if ((root->right == NULL) && (root->left != NULL)) // One left child node
{
node *temp = root;
root = root->left;
delete temp;
temp = NULL;
}
else if ((root->left == NULL) && (root->right!= NULL)) // One right child node
{
node *temp = root;
root = root->right;
delete temp;
temp = NULL;
}
else // Two children
{
node *temp = findMin(root->right); // Finds smallest value in right subtree
root->val = temp->val;
root->right = Delete(root->right, temp->val);
}
}
return root;
}
Below is my Destructor, which is giving me a SIGABRT (I'm using Xcode)
/**********************************************
* Destructor
**********************************************/
node::~node()
{
if (left != NULL) delete left;
if (right != NULL) delete right;
}
What my code is actually doing is not only deleting the node I intend to delete, but its child node. What could I be doing wrong? Is it an error with memory allocation? Is it an error with how I set the value to the child node?
You need to null your pointers to left and right before deleting a node.
You call:
node *temp = root;
root = root->left;
delete temp;
temp = NULL;
When you "delete temp" you are deleting a node which still points to root->left and root->right and your destructor insures they are also removed. You should instead do something like this:
node *temp = root;
root = root->left;
temp->left = NULL;
temp->right = NULL;
delete temp;
temp = NULL;
Also in your destructor you don't need to check if they are equal to null since delete already preforms this check.

How to combine findMin() and delete() to remove smallest node in a BST?

I have a recRemove function that recursively removes the given node. I also have a findMin function that finds the smallest node in the BST. I'm having trouble merging the two so that I can remove the smallest(or largest) node. This is what I tried doing but it just returned garbage: Full code: https://pastebin.com/HCVsUZ4S
//remove min node in BST
node * extractMin()
{
return recRemove(root, findMin(root));
}
//delete node from tree
node * recRemove(node * root, double data)
{
//3 cases: no children, one child, 2 children
if (root == NULL)
{
return NULL;
}
else if (data < root->data)
{
root->left = recRemove(root->left, data);
}
else if(data > root->data)
{
root->right = recRemove(root->right, data);
}
else
{
if (root->right == NULL && root->left == NULL) //no children
{
delete root;
root = NULL;
return root;
}
else if(root->left == NULL) //only right child
{
temp = root;
root = root->right;
delete temp;
return root;
}
else if(root->right == NULL) //only left child
{
temp = root;
root = root->left;
delete temp;
return root;
}
else //2 children
{
temp->data = findMin(root->right);
root->data = temp->data;
root->right = recRemove(root->right, temp->data);
}
}
return root;
}
//find min node in BST
double findMin(node * p)
{
if(p == NULL)
{
return -1;
}
else
{
//in a balanced BST the minimum node is the leftmost node so,
//we traverse the left subtree until we get to the leftmost node and return and remove it.
temp = p;
while(temp->left != NULL)
{
temp = temp->left;
}
return temp->data;
}
}
sorry , can't write comments yet (will delete this later)
Where is temp defined? If it is a global variable than this is probably the issue...
Edit:
Have now seen the pasebin.....
temp is a member variable. Change it to a local variable.
Make sure to delete it before leaving the function. (best use std::unique_ptr<>)

How do I access a pointer from within a nested class?

This class's purpose is to emulate the functions of a Binary Search Tree. In the below code, I am trying to adapt it from a struct and a bunch of functions, into a wrapper class, called BST. One thing I am not sure of however, is how to access 'root' from within the node struct. Root is currently declared within the BST class.
class bst
{
public:
struct Node
{
public:
int data;
struct Node *left;
struct Node *right;
Node* FindMin(Node* root)
{
while(root->left != NULL) root = root->left;
return root;
}
Node* Insert(Node *root,int data)
{
if(root == NULL) {
root = new Node();
root->data = data;
root->left = root->right = NULL;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
else if(data <= root->data)
root->left = Insert(root->left,data);
else
root->right = Insert(root->right,data);
return root;
}
Node* Delete(struct Node *root, int data)
{
if(root == NULL) return root;
else if(data < root->data) root->left = Delete(root->left,data);
else if (data > root->data) root->right = Delete(root->right,data);
//Value found
else {
// Case 1: No child
if(root->left == NULL && root->right == NULL)
{
delete root;
root = NULL;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
//Case 2: One child
else if(root->left == NULL)
{
struct Node *temp = root;
root = root->right;
delete temp;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
else if(root->right == NULL)
{
struct Node *temp = root;
root = root->left;
delete temp;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
// case 3: 2 children
else
{
struct Node *temp = FindMin(root->right);
root->data = temp->data;
root->right = Delete(root->right,temp->data);
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
}
return root;
}
//# of Nodes in tree
void size(Node *root)
{
//Check if end
if(root == NULL) return;
//Not end
else
{
bstSize = bstSize + 1;
size(root->left); //Visit left subtree
size(root->right); // Visit right subtree
}
}
void height(Node *root, int temp)
{
//Check if end
if(root == NULL)
{
if(temp > bstHeight)
{
bstHeight = temp;
}
return;
}
//Not end
else
{
temp = temp + 1;
height(root->left, temp); //Visit left subtree
height(root->right, temp); // Visit right subtree
}
}
//Function to visit nodes in Inorder
void show()
{
if(root == NULL) return;
show(root->left); //Visit left subtree
printf("%d ",root->data); //Print data
show(root->right); // Visit right subtree
}
void check(Node *root)
{
//End of a 'branch'
if(root == NULL) return;
int value = 0;
value = root->data;
//Checking left subtree
if(value < root->left->data)
{
//Tree is NOT valid
valid = 0;
}
//Checking right subtree
if(value > root->right->data)
{
//Tree is NOT valid
valid = 0;
}
check(root->left); //Visit left subtree
printf("%d ",root->data); //Print data
//check(root->right); // Visit right subtree
}
};
Node* root = NULL;
};
Specifically, in the show function. It's not as simple as putting it into Node with the rest of the functions, as root needs to be unique, and new Node is called at least once. Show will not compile in the current state, and I'm not sure where to proceed from here.
Though the comment says everything, let me give an additional hint:
When you want to keep your code as similar as possible to what you have now, try to add a constructor to the Node class that expects a pointer or reference (preferable) to the root and check, that each time you create a Node, you give the root to the constructor.
By the way, it might even be a better approach to look at some simple Node-based data structure implementations in C++, for example in the thread
Simple linked list in C++

BST node removal function doing sth I don't understand

So I am writing a BST node removal function, but I cannot figure out a problem:
I have this node-data structure:
struct webentry
{
char * topic;
char * keyword;
char * url;
char * summary;
char * review;
int rating;
};
The problem occurs at the point where the node has a two children and its right child has a left child (meaning I need to find the inorder successor and replace it with):
else if ((root->right != NULL) && (root->left !=NULL) && (root->right->left !=NULL))
{
node*tempr = root->right;
node*templ = root->left;
delete root->data.topic;
delete root->data.keyword;
delete root->data.url;
delete root->data.summary;
delete root->data.review;
delete root;
root = findis(tempr);
root->right = tempr;
root->left = templ;
return 1;
}
I wrote a findis function to deal with the inorder successor situation:
node* program4::findis(node* &root)
{
/* cout to figure out what's going on
cout<<"Topic: "<<root->data.topic<<endl; Finds it here
cout<<"Keyword: "<<root->data.keyword<<endl; Finds it here
*/
if ((root->left==NULL) && (root->right ==NULL))
{
node*temp = root;
delete root;
root = NULL;
/*
cout<<"Topic: "<<temp->data.topic<<endl; Empty
cout<<"Keyword: "<<temp->data.keyword<<endl; Finds
*/
return temp;
}
else if ((root->left == NULL) && (root->right != NULL))
{
node*temp= root;
node*tempn = root->right;
delete root;
root = tempn;
/*
cout<<"Topic: "<<root->data.topic<<endl;
cout<<"Keyword: "<<root->data.keyword<<endl;
*/
return temp;
}
else
{
return findis(root->left);
}
The problem is: When the node inorder successor returns, topic part becomes NULL, everything else stays the same. I have used GDB to figure out where it deletes the contents of topic, and it is right where I marked, right after the if condition meets and deletes the root in the findis function. It doesn't delete any other data of the the node, I don't know why it even deletes it. Can anyone see what is happening here?

double free or corruption when implement binary tree

update:
add more code as asked.pasted to the end of question. Thanks everyone who stops.
current code is fine to delete a leaf, but come to Root, it can not delete.
====
update:
I revise the code, change removeRootMatch to
tmp = Root;
Root = tmp->Right;
tmp->Right = NULL;
delete tmp;
and no error but it does not delete the Node.
=====
The program is simple do the following step:
find min value of a binary tree;
record the min value in a vector;
delete the node with min value in the tree;
repeat 1-3 till the tree is empty.
I have removeNode()function, which will call removeRoot function(check code below),if the one needed to be removed is Root. But I have trouble with this function. I am doing some debug and found it is something wrong with removeRootMatch function. It give an error when run. the error I got is The error I got is *** glibc detected *** ./bintree: double free or corruption (fasttop): 0x0000000000727060 ***, any one can help me?
The tree is defined as following, language is c++
typedef struct myNode* LPNode;
typedef struct myNode Node;
struct myNode
{
double key;
LPNode Left; //left subtree
LPNode Right; //right subtree
};
Main part of program is as following:
nmax is initialed as 0,
sortedvector is alloacted a vector with space as large as the total nodes in the tree,
min is initialed as 99999.
minValue will return the min value of tree.
compareDouble(a,b) will return 1 if a < b,return 2 if a > b,return 3 if equal
code as following
void removeRootMatch(LPNode Root)
{
LPNode tmp = MakeNewNode(Root->key);
tmp->Left = Root->Left;
tmp->Right = Root->Right;
//no child
if(Root->Left==NULL && Root->Right == NULL) {
Root=NULL;
delete Root;
} else if(Root->Left==NULL && Root->Right!=NULL){ //one right child
//delete Root;
Root = tmp->Right;
tmp->Right = NULL;
delete tmp;
} else {
printf("Remove root bug!\n");
}
}
This is the function call removeNode function.
//compare double
int compareDouble(double a,double b)
{
if(a-b<-EPSILON) //a<b
return 1;
else if(a-b>EPSILON)//a>b
return 2;
else
return 3;
}
//find the min key in a tree
double minValue(LPNode Root,double min)
{
if(Root == NULL)
return min;
if(compareDouble(Root->key,min)==1)
min = Root->key;
min = minValue(Root->Left, min);
min = minValue(Root->Right, min);
return min;
}
//remove root
void removeRootMatch(LPNode& Root)
{
LPNode tmp = MakeNewNode(Root->key);
tmp->Left = Root->Left;
tmp->Right = Root->Right;
//no child
if(Root->Left==NULL && Root->Right == NULL) {
Root=NULL;
delete Root;
} else if(Root->Left==NULL && Root->Right!=NULL){ //one right child
double k = Root->key;
Root = tmp->Right;
tmp->Right = NULL;
delete tmp;
//tmp=tmp->Right;
//Root->Right = NULL;
//delete Root;
//Root = tmp;
} else {
printf("Remove root bug!\n");
}
}
//remove a node
void removeMatch(LPNode& Root,LPNode match,bool left)
{
//no child
if(match->Left==NULL && match->Right == NULL){
double k = match->key;
left==true?
Root->Left=NULL:
Root->Right=NULL;
delete match;
if(!Root->Left)printf("%f ",k);
}
else if(match->Left==NULL && match->Right!=NULL){//one right child
double k = match->key;
left==true?
Root->Left=match->Right:
Root->Right=match->Right;
delete match;
if(!Root->Left)printf("%f ",k);
} else {
printf("Remove root bug!\n");
}
}
//delete a node
void removeNode(LPNode Root,double min)
{
if(compareDouble(min,Root->key)==3){
removeRootMatch(Root);
}else if(compareDouble(min,Root->key)==1 && Root->Left != NULL) {
compareDouble(min,Root->Left->key)==3 ?
removeMatch(Root,Root->Left,true):
removeNode(Root->Left,min);
}else if(compareDouble(min,Root->key)==2 && Root->Right != NULL){
compareDouble(min,Root->Right->key)==3 ?
removeMatch(Root,Root->Right,false):
removeNode(Root->Right,min);
}else{
printf("Remove bug1!\n");
}
}
//call minValue to find the min key
//record the min key in a vector
//call removeNode to delete the Node
//repeat till the tree is empty
void problem1(LPNode Root,double* sortedvector,int& nmax)
{
double min;
//while(Root!=NULL)
for(int i=0;i<3;i++)
{
min = MAX;
sortedvector[nmax] = minValue(Root,min) ;
printf("inv%f\n",sortedvector[nmax]);
removeNode(Root,sortedvector[nmax]);
nmax++;
}
printf("The tree is empty");
}
If your function removeNode may adjust the Root, then your function is not declared properly.
void removeRootMatch(LPNode Root)
You are passing a pointer to Root. Inside the removeRootMatch function, you are working on a copy of the pointer. So code like this inside of the removeRootMatch function:
Root = tmp->Right;
tmp->Right = NULL;
delete tmp;
does not change the Root node when the function returns.
To address this issue, you should pass the Root pointer by reference:
void removeRootMatch(LPNode& Root)