BST Deletion c++ - c++

I have a code for deletion of a node in BST. This code shows memory overflows for some values. i cant figure out the problem. isequal() function returns true if both char arrays have same data and compare() functions returns true or false on the basis of values in temp->name and name. It returns true if first argument have bigger values.
void delete_data(char *name)
{
bool found = false;
tree *temp;
tree *parent;
temp=root;
while(temp != NULL)
{
if(isequal(temp->file_name,name)==true)
{
found = true;
break;
}
else
{
parent = temp;
if(compare(name,temp->file_name)==true)
temp=temp->right;
else
temp = temp->left;
}
}
if(!found)
{
cout<<"Data not found"<<endl;
return;
}
if((temp->left==NULL&&temp->right!=NULL)||(temp->left!=NULL&&temp->right==NULL))
{
if(temp->left == NULL && temp->right != NULL)
{
if(parent->left == temp)
{
parent->left = temp->right;
delete temp;
}
else
{
parent->right = temp->right;
delete temp;
}
}
else
{
if(parent->left == temp)
{
parent->left = temp->left;
delete temp;
}
else
{
parent->right = temp->left;
delete temp;
}
}
return;
}
if( temp->left == NULL && temp->right == NULL)
{
if(parent->left == temp) parent->left = NULL;
else parent->right = NULL;
delete temp;
return;
}
if (temp->left != NULL && temp->right != NULL)
{
tree *chkr;
if(parent==NULL || parent->left==temp)
{
chkr=temp->right;
while(chkr->left!=NULL)
chkr=chkr->left;
if(parent!=NULL)
parent->left=temp->right;
else
root=temp->right;
chkr->left=temp->left;
temp->left=temp->right=NULL;
delete temp;
}
else if(parent->right==temp)
{
chkr=temp->left;
while(chkr->right!=NULL)
chkr=chkr->right;
parent->right=temp->left;
chkr->right=temp->right;
temp->left=temp->right=NULL;
delete temp;
}
return;
}
}

I took a quick look at it, and it seems that you only initialize parent in the non-trivial case.
If the root is the node that you want to delete, parent is uninitialized. You check if parent is something non-null only in the case where temp has 2 descendants. I would guess that this is the problem.

Related

Freeing memory when deleting node from BST

I am having difficulty releasing memory for my BST deletion. The algorithm itself works, so long as I don't include the "delete" keyword. As soon as I do, it causes this error: malloc: * error for object 0x7fec6a4026a0:
pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Abort trap: 6
Here is my code, along with the single "delete" keyword. I've also included other locations where I've tried placing the delete keyword. I understand that you must free up the memory in C++ to prevent memory leaks. I have a feeling that the recursive call may be causing the problem, but I can't pinpoint it.
bool AVLTree::deleteNode(string ss, AVLNode* starting){
AVLNode* curr = starting;
AVLNode* parent = starting->parent;
while (curr != nullptr) {
if (curr->ssn == ss) {
// Remove leaf
if (curr->right == nullptr && curr->left == nullptr) {
// Remove root
if (parent == nullptr) {
root = nullptr;
}
else if (parent->left == curr) {
parent->left = nullptr;
}
else {
parent->right = nullptr;
}
// IVE TRIED PUTTING DELETE HERE
}
// Remove node with two children
else if (curr->right != nullptr && curr->left != nullptr) {
// Find succesor
AVLNode* succ = curr->right;
while (succ->left != nullptr) {
succ = succ->left;
}
// Copy
curr->ssn = succ->ssn;
curr->name = succ->name;
deleteNode(succ->ssn, curr->right);
}
// Remove node with one children
else {
// If has left child
if (curr->left != nullptr) {
if (parent == nullptr) {
root = curr->left;
}
else if (parent->left == curr) {
parent->left = curr->left;
}
else {
parent->right = curr->left;
}
}
else if (curr->right != nullptr) {
if (parent == nullptr) {
root = curr->right;
}
else if (parent->left == curr) {
parent->left = curr->right;
}
else {
parent->right = curr->right;
}
}
// IVE TRIED PUTTING DELETE HERE
}
delete curr; // THIS IS CAUSING THE PROBLEM
return true;
}
else if ((curr->ssn.compare(ss)) < 0) {
parent = curr;
curr = curr->right;
}
else {
parent = curr;
curr = curr->left;
}
}
return false;
}
// Insert function
bool AVLTree::insert(string ss, string na){
AVLNode* curr = root;
// Construct new AVL Node
AVLNode* newNode = new AVLNode(ss, na);
// If root is empty, insert
if (curr == nullptr) {
root = newNode;
return true;
}
while (curr != nullptr) {
if (curr->ssn.compare(newNode->ssn) == 0) {
delete newNode;
return false;
}
// Go right
if (newNode->ssn.compare(curr->ssn) > 0) {
// Check to see if we can insert, currs right child is null
if (curr->right == nullptr) {
curr->right = newNode;
newNode->parent = curr;
break;
}
else {
curr = curr->right;
}
}
// Go left
else {
// Check to see if we can insert
if (curr->left == nullptr) {
curr->left = newNode;
newNode->parent = curr;
break;
} else {
curr = curr->left;
}
}
}
return true;
}

Error when Deleting Node from BST

This genuinely has me stumped. I have a binary search tree of citys that is ordered by the city name. A city also contains the population and GPS coordinates. I want to be able to remove nodes from the tree by City name or city coordinates. I have the delete by name working fine but the GPS coordinates does not work.
When I remove a node by GPS I get a stack-overflow when I try to print the binary tree. Below is some of my code. I cannot understand how it will work fine if I delete by name but not if I delete by coordinates as I am using the same delete method.
The exact error I get is "Unhandled exception at 0x013214D6 in EXE: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00152FFC)." This occurs in my print function after I delete by coordinates but not if I delete by name.
bool BinaryTree::DeleteByName(string city)
{
if (GetRoot() != NULL)
{
return (DeleteByName(GetRoot(), city));
}
return false;
}
TreeNode* BinaryTree::DeleteByName(TreeNode *node, string city)
{
if (node == NULL)
{
return node;
}
else if (city < node->Data.name)
{
node->Left = DeleteByName(node->Left, city);
}
else if (city > node->Data.name)
{
node->Right = DeleteByName(node->Right, city);
}
else
{
if (node->Left == NULL && node->Right == NULL)
{
delete node;
node = NULL;
}
else if (node->Left == NULL)
{
TreeNode* temp = node;
node = node->Right;
delete temp;
}
else if (node->Right == NULL)
{
TreeNode* temp = node;
node = node->Left;
delete temp;
}
else
{
cout << "Else";
TreeNode* temp = MinPtr(node->Right);
node->Data = temp->Data;
node->Right = DeleteByName(node->Right, temp->Data.name);
}
}
return node;
}
bool BinaryTree::DeleteByCoord(pair<double, double> coords)
{
if (GetRoot() == NULL)
{
return false;
}
else
{
return DeleteByCoord(GetRoot(), coords);
}
}
bool BinaryTree::DeleteByCoord(TreeNode* node, pair<double, double> coords)
{
bool result;
if (node == NULL)
{
return false;
}
else
{
if (node->Data.coordinates.first == coords.first && node->Data.coordinates.second == coords.second)
{
return (DeleteByName(node, node->Data.name));
}
result = DeleteByCoord(node->Left, coords);
if (result == true)
{
return result;
}
return DeleteByCoord(node->Right, coords);
}
}
void BinaryTree::Insert(City city)
{
TreeNode* temp = new TreeNode(city);
if (GetRoot() == NULL)
{
root = temp;
}
else
{
Insert(temp, GetRoot());
}
}
void BinaryTree::Insert(TreeNode* toAdd, TreeNode* addHere)
{
if (toAdd->Data < addHere->Data)
{
if (addHere->Left != NULL)
{
Insert(toAdd, addHere->Left);
}
else
{
addHere->Left = toAdd;
}
}
else if (toAdd->Data > addHere->Data)
{
if (addHere->Right != NULL)
{
Insert(toAdd, addHere->Right);
}
else
{
addHere->Right = toAdd;
}
}
}
void BinaryTree::InOrderTraversal(TreeNode* node)
{
if (node != NULL)
{
InOrderTraversal(node->Left);
cout << node->Data << endl;
InOrderTraversal(node->Right);
}
}
void BinaryTree::InOrderTraversal()
{
InOrderTraversal(GetRoot());
}
TreeNode* BinaryTree::GetRoot()
{
return root;
}
TreeNode* BinaryTree::MinPtr(TreeNode* node)
{
while (node->Left != NULL)
{
node = node->Left;
}
return node;
}
When you delete the node you also need to update parent pointer that points to deleted node. Pay attention here:
when you call DeleteByName directly it searches required node and returns NULL pointer which automatically set to parent node pointer:
else if (city < node->Data.name)
{
node->Left = DeleteByName(node->Left, city);
}
else if (city > node->Data.name)
{
node->Right = DeleteByName(node->Right, city);
}
but when you call DeleteByName from coordinates method you do not reset parent's Left/Right pointers:
if (node->Data.coordinates.first == coords.first && node->Data.coordinates.second == coords.second)
{
return (DeleteByName(node, node->Data.name));
}
in its turn as DeleteByName already receives required node, it does not perform recursive call and does not reset parent's pointers either:
else
{
if (node->Left == NULL && node->Right == NULL)
{
delete node;
node = NULL;
}
//... same here
}
NOTE: There are many more problems in your code. Some that strike the eye:
DeleteByName returns pointer, but DeleteByCoord returns bool, you use pointer as a boolean type in DeleteByCoord
Avoid to compare doubles directly, the comparison result can be wrong. See the question and explanation for the details.

BST deleting root node with two children

I coded case #2 in delete_node but am getting a segmentation error. I'm using the predecessor to delete the node. I'm not sure what happens when I am removing the root node with two children. Is it the same as deleting a non-root node with two children except you don't have to connect the predecessor's children? I think that's how I've coded it...
bool delete_node(Node*& root, KType key) {
// find target node to delete
Node* target = find(key, root);
if (!target) return false;
// find parent of target
Node* parent = find_parent(root, target);
// case 1: target is a leaf
if (target->left == NULL && target->right == NULL) {
// set parent's child pointer
if (parent != NULL) {
if ( parent->left == target )
parent->left = NULL;
else
parent->right = NULL;
}
else
root = NULL;
// free target
delete target;
return true;
}
// case 2: target has two children
else if (target->left != NULL && target->right != NULL) {
if (parent != NULL) {
//find predecessor
Node* temp = target->left;
while (temp != NULL) {
temp = temp->right;
}
// find predecessor's parent
Node* predecessorParent = find_parent(root, temp);
target->key = temp->key;
if (predecessorParent->left == temp) {
predecessorParent->left = temp->left;
} else {
predecessorParent->right = temp->left;
}
delete(temp);
return true; // return true when you're done.
} else {
//find predecessor
Node* temp = target->left;
while (temp != NULL) {
temp = temp->right;
}
target->key = temp->key;
delete(temp);
return true; // return true when you're done.
}
}
// case 3: target has only left child
else if (target->left != NULL) {
// set parent's child pointer
if (parent != NULL) {
if ( parent->left == target )
parent->left = target->left;
else
parent->right = target->left;
}
else
root = target->left;
// free target
delete target;
return true;
}
// case 4: target has only right child
else {
// set parent's child pointer
if (parent != NULL) {
if (parent->left == target)
parent->left = target->right;
else
parent->right = target->right;
}
else
root = target->right;
// free target
delete target;
return true;
}
return false;
}
find_parent function:
/**
* Finds the parent of node in the tree rooted at rootNode
*/
Node* find_parent(Node* rootNode, Node* node) {
if ( rootNode == NULL || rootNode == node ) {
return NULL;
}
else if ( rootNode->left == node || rootNode->right == node ) {
return rootNode;
}
else if (node->key < rootNode->key) {
return find_parent(rootNode->left, node);
}
else {
return find_parent(rootNode->right, node);
}
}

c++ Binary Search tree Deletion

So, my question is I don't understand why this doesn't work. I commented below where it is saying that parent is never initialized when it clearly is. Am I doing pointers wrong, am I getting the logic backwards am I so far off it would be better to just start from scratch? This is the most difficult assignment I have encountered so any help at all would be very beneficial.
void Dictionary::remove(string word)
{
if(root == NULL)
{
cout << "list is empty\n";
return;
}
DictionaryNode *curr = root;
DictionaryNode *parent = NULL;`
while(curr != NULL)
{
if(curr->word == word)
break;
else
{
parent = curr;
if(word > curr->word)
curr = curr->right;
else
curr = curr->left;
}
}
//LEAF node.
if(curr->left == NULL && curr->right == NULL)
{
if(parent->left == curr) // Right here is an access violation. Which doesn't //make sense.
{
parent->left = NULL;
}
else
{
parent->right = NULL;
}
delete curr;
}
/*
* Node has a single child LEFT or RIGHT
*/
if((curr->left == NULL && curr->right != NULL) || (curr->left != NULL && curr->right == NULL))
{
if(curr->left == NULL && curr->right != NULL)
{
if(parent->left == curr) //if(parent->left == curr) //says parent is //not intialized
{
parent->left = curr->right;
delete curr;
}
else
{
parent->right = curr->right;
delete curr;
}
}
else
{
if(parent->left == curr)
{
parent->left = curr->left;
delete curr;
}
else
{
parent->right = curr->left;
delete curr;
}
}
}
if (curr->left != NULL && curr->right != NULL)
{
DictionaryNode* temp;
if(parent == NULL || parent->left==curr)
{
temp = curr->right;
while(temp->left!=NULL)
temp = temp->left;
if(parent!=NULL)
parent->left = curr->right;
else
root = curr->right;
temp->left = curr->left;
curr->left = curr->right=NULL;
delete curr;
}
else if(parent->right==curr)
{
temp = curr->left;
while(temp->right!=NULL)
temp = temp->right;
parent->right=curr->left;
temp->right = curr->right;
curr->left = curr->right=NULL;
delete curr;
}
}
}
1.
First thing I see:
while(curr != NULL)
{
//stuff
}
As it is written, it seems that at the end of your loop curr == NULL
Lazy me had to look at the content of your loop to notice the break. A break could be even less noticeable with a bigger block in the loop.
This is not a good practice.
Use a bool (e.g.: bool isNodeFound;), it's cheap (one bit) and makes it more clear.
while(curr != NULL && !isNodeFound) is more clear of your intentions, at first sight, without looking at the content of your loop.
2.What if indeed you don't hit the break in the loop and curr == NULL ?
Your next instruction curr->left would fail!
Seems like the Boolean will be useful again!
if(!isNodeFound)
{
//log error if you can "cannot remove node because it is not in dictionary"
return false; //make your function a bool to return if it succeeded or not
}
Try to analyze the rest of your code with the same state of mind, more clarity and testing, let me know if it works.
everyone. One day, I searched this question when i needed function to remove tree node in BST. So, this question is nice, i edited and checked above code then code really operated successfully. Above code missed some instances, follow me below explanations:
First, deleted node is LEAF NODE. You missed a instance that node is either root or leaf node (i.e. BST only have a node). So, parent is NULL and parent->left/right is invalid.
Second, deleted node has a subtree left or right. So, this is similar with First if deleted node is root.
Third, deleted node have left and righr subtree. You considered "parent" but you shouldn't use "if(parent == NULL || parent->left==curr)" as if parent = NULL so that parent->left is invalid. You should make " if(parent == NULL){...} else{if(parent->left == curr)...}".
Finally, use if...else-if...else instead of using if...if...if because you deleted "curr", then you won't know "curr" point anywhere and "if" next still will be checked with "curr" errors.
Below edited code for anyone need,
void Dictionary::remove(string word)
{
if(root == NULL)
{
cout << "list is empty\n";
return;
}
DictionaryNode *curr = root;
DictionaryNode *parent = NULL;
while(curr != NULL)
{
if(curr->word == word)
break;
else
{
parent = curr;
if(word > curr->word)
curr = curr->right;
else
curr = curr->left;
}
}
//LEAF node.
if(curr->left == NULL && curr->right == NULL)
{
if (parent == NULL) {
delete curr;
} else {
if(parent->left == curr) // Right here is an access violation. Which doesn't //make sense.
{
parent->left = NULL;
}
else
{
parent->right = NULL;
}
delete curr;
}
}
/*
* Node has a single child LEFT or RIGHT
*/
else if((curr->left == NULL && curr->right != NULL) || (curr->left != NULL && curr->right == NULL))
{
if(curr->left == NULL && curr->right != NULL)
{
if (parent == NULL) {
root = curr->right;
curr->right = NULL;
delete curr;
} else {
if(parent->left == curr) //if(parent->left == curr) //says parent is //not intialized
{
parent->left = curr->right;
delete curr;
}
else
{
parent->right = curr->right;
delete curr;
}
}
}
else
{
if (parent == NULL) {
root = curr->left;
curr->left = NULL;
delete curr;
} else {
if(parent->left == curr)
{
parent->left = curr->left;
delete curr;
}
else
{
parent->right = curr->left;
delete curr;
}
}
}
}
else
{
DictionaryNode* temp;
if(parent == NULL)
{
temp = curr->right;
while(temp->left!=NULL)
temp = temp->left;
if(parent!=NULL)
parent->left = curr->right;
else
root = curr->right;
temp->left = curr->left;
curr->left = curr->right=NULL;
delete curr;
} else {
if(parent->left==curr){
temp = curr->right;
while(temp->left!=NULL)
temp = temp->left;
if(parent!=NULL)
parent->left = curr->right;
else
root = curr->right;
temp->left = curr->left;
curr->left = curr->right=NULL;
delete curr;
}
else if(parent->right==curr)
{
temp = curr->left;
while(temp->right!=NULL)
temp = temp->right;
parent->right=curr->left;
temp->right = curr->right;
curr->left = curr->right=NULL;
delete curr;
}
}
}
}
Hope this code that can help other people when they need!

BST code is not working with large number

I have a very frustrated situation with my BST code:
vector<int> order;
BinarySearchTree tree;
for (int i=0; i<1000; ++i) {
int j = rand()%1000;
order.push_back(j);
}
for (int i = 0; i < 1000; ++i) {
tree.insert(order[i]);
}
while(!tree.isEmpty()) {
cout << tree.min() << endl;
tree.remove(tree.min());
}
the code is working perfectly fine with small number of i, say 10, or 100. However, it is stop working when i is 1000.
the insert function is as follows
void BinarySearchTree::insert(int d)
{
tree_node* t = new tree_node;
tree_node* parent;
t->data = d;
t->left = NULL;
t->right = NULL;
parent = NULL;
// is this a new tree?
if(isEmpty()) root = t;
else
{
//Note: ALL insertions are as leaf nodes
tree_node* curr;
curr = root;
// Find the Node's parent
while(curr)
{
parent = curr;
if(t->data > curr->data) curr = curr->right;
else curr = curr->left;
}
if(t->data <= parent->data)
parent->left = t;
else
parent->right = t;
}
}
In response to the comments, i am going to post all the code. :)
void BinarySearchTree::remove(int d)
{
//Locate the element
bool found = false;
if(isEmpty())
{
cout<<" This Tree is empty! "<<endl;
return;
}
tree_node* curr;
tree_node* parent;
curr = root;
//parent = root;
while(curr != NULL)
{
if(curr->data == d)
{
found = true;
break;
}
else
{
parent = curr;
if(d>curr->data) curr = curr->right;
else curr = curr->left;
}
}
if(!found)
{
cout<<" Data not found! "<<endl;
return;
}
// 3 cases :
// 1. We're removing a leaf node
// 2. We're removing a node with a single child
// 3. we're removing a node with 2 children
// Node with single child
if((curr->left == NULL && curr->right != NULL)|| (curr->left != NULL
&& curr->right == NULL))
{
if(curr->left == NULL && curr->right != NULL)
{
if (curr == root) {
root = curr->right;
delete curr;
}
else {
if(parent->left == curr)
{
parent->left = curr->right;
delete curr;
}
else
{
parent->right = curr->right;
delete curr;
}
}
}
else // left child present, no right child
{
if (curr==root) {
root = curr->left;
delete curr;
}
else {
if(parent->left == curr)
{
parent->left = curr->left;
delete curr;
}
else
{
parent->right = curr->left;
delete curr;
}
}
}
return;
}
//We're looking at a leaf node
if( curr->left == NULL && curr->right == NULL)
{
if (curr == root) {
root = NULL;
delete curr;
return;
}
else {
if(parent->left == curr) parent->left = NULL;
else parent->right = NULL;
delete curr;
return;
}
}
//Node with 2 children
// replace node with smallest value in right subtree
if (curr->left != NULL && curr->right != NULL)
{
tree_node* chkr;
chkr = curr->right;
if((chkr->left == NULL) && (chkr->right == NULL))
{
curr = chkr;
delete chkr;
curr->right = NULL;
}
else // right child has children
{
//if the node's right child has a left child
// Move all the way down left to locate smallest element
if((curr->right)->left != NULL)
{
tree_node* lcurr;
tree_node* lcurrp;
lcurrp = curr->right;
lcurr = (curr->right)->left;
while(lcurr->left != NULL)
{
lcurrp = lcurr;
lcurr = lcurr->left;
}
curr->data = lcurr->data;
delete lcurr;
lcurrp->left = NULL;
}
else
{
tree_node* tmp;
tmp = curr->right;
curr->data = tmp->data;
curr->right = tmp->right;
delete tmp;
}
}
return;
}
}
and the min() function
int BinarySearchTree::min()
{
tree_node *p=root;
while (p->left != NULL)
p=p->left;
return (p->data);
}
Looks like the last four lines have negated logic of the for loop.
The for loop says:
new val is larger go right else left.
The tree placement says:
new val is larger place left else place right.
Also I don't see your remove code, but the it may be affected by the wrong ordering.
Also try initializing rand before using it:
srand (time(NULL));
You need to improve on your random function. Try using int j = rand() instead.
EDIT: you have duplicate minimum values. With the code below you remove the top most node with minimum value.
while(curr != NULL)
{
if(curr->data == d)
{
found = true;
break;
}
else
{
parent = curr;
if(d>curr->data) curr = curr->right;
else curr = curr->left;
}
}
try the following code instead.
tree_node* left_most_duplicate;
while (curr != NULL)
{
if (d>curr->data) curr = curr->right;
else curr = curr->left;
if (curr->data == d)
{
parent = curr;
left_most_duplicate = curr;
found = true;
break;
}
}
curr = left_most_duplicate;