Following is a piece of my code for deleting a node from a BST. It is a non-recursive code.
I have applied all the possible conditions.
However when I run my code, it stops as if stuck somewhere in an infinite loop or ending up at a point where my pointer is pointing to NULL.However I am unable to identify it.
Any help would be appreciated.
template <class T>
void bst<T>::delete_node(T key1)
bst_node<T>* delNode = search(key1); //delNode is the node I wish to delete
if(delNode!=root)
{
if((delNode->left == NULL) && (delNode->right == NULL)) // node to be deleted has no children
{
delNode = NULL;
}
else if((delNode->left!=NULL) && (delNode->right == NULL)) //node to be deleted has exactly one child
{
if(delNode->parent->left == delNode)
{
delNode->parent->left = delNode->left;
delNode = NULL;
}
else if(delNode->parent->right == delNode)
{
delNode->parent->right = delNode->left;
delNode = NULL;
}
}
else if((delNode->right!= NULL) && (delNode->left == NULL))
{
if(delNode->parent->left == delNode)
{
delNode->parent->left = delNode->right;
delNode = NULL;
}
else if(delNode->parent->right == delNode)
{
delNode->parent->right = delNode->right;
delNode = NULL;
}
}
else if((delNode->right!=NULL)&&(delNode->left != NULL)) //if has two children
{
bst_node<T>* temp = delNode;
bst_node<T>* trav = delNode->right;
if((trav->right == NULL)&&(trav->left == NULL))
{
delNode->value = trav->value;
delNode->key = trav->key;
trav = NULL;
}
else
{
bst_node<T>* pred = trav;
while(trav!=NULL)
{
pred = trav; //smallest node in right subtree
trav=trav->left;
}
delNode->value = pred->value;
delNode->key = pred->key;
pred = NULL;
}
}
}
else if(delNode==root)//node to be deleted is Root
{
if((delNode->left==NULL)&&(delNode->right==NULL))
root = NULL;
else if((delNode->left!=NULL) && (delNode->right == NULL)) //root has exactly one child
{
root = delNode->left;
delNode = NULL;
}
else if((delNode->right!= NULL) && (delNode->left == NULL))
{
root = delNode->right;
delNode = NULL;
}
else if((delNode->right!=NULL)&&(delNode->left!=NULL)) {
bst_node<T>* temp = delNode;
bst_node<T>* trav = delNode->right;
if((trav->right == NULL)&&(trav->left == NULL))
{
delNode->value = trav->value;
delNode->key = trav->key;
trav = NULL;
}
else
{
bst_node<T>* pred = trav;
while(trav!=NULL)
{
pred = trav; //smallest node in right subtree
trav=trav->left;
}
delNode->value = pred->value;
delNode->key = pred->key;
pred = NULL;
}
}
}
}
In the part:
else if((delNode->right!=NULL)&&(delNode->left != NULL)) //if has two children
when if is taken:
if((trav->right == NULL)&&(trav->left == NULL))
the code copies the values from trav to delNode and sets trav to NULL:
delNode->value = trav->value;
delNode->key = trav->key;
trav = NULL;
but doesn't set delNode->right to NULL, as it should because trav didn't have any children.
the very next else statement which seeks for the most left node commits a similar error, because parent node's member left isn't set to NULL.
The next big part of the code which deals with deletion of only root node, seems to have identical problems, due to apparent copy-pasted (cough!) code.
Related
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;
}
I've got a non-recursive pseudocode for deleting a node (without 2 children case at the moment), which I have to implement. Everything seems to be OK, except the situation when I want to delete a root.
The pseudocode:
delete(root, key)
{
parent = NULL;
p = root; //p - node to delete
while( (p != NULL) && (key != p->data) )
{
parent = p;
if( p->data < key ) p = p->right;
else p = p->left;
}
if( p == NULL ) return;
if( (p->right == NULL) && (p->left == NULL) ) // deleted node p is a leaf
{
if(p == root)
{
root = NULL; // deleted leaf is a root
return;
}
if( parent->right == p) parent->right = NULL;
else parent->left = NULL;
return;
}
if( p->right == NULL ) // p node to delete has only left subtree
{
if( parent->right == p ) parent->right = p->left;
else parent->left = p->left;
return;
}
if( p->left == NULL ) // p node to delete has only right subtree
{
if( parent->right == p ) parent->right = p->right;
else parent->left = p->right;
return;
}
}
And here is my implementation:
struct BstNode
{
int data;
BstNode *left, *right;
};
void Remove(BstNode **root, int key)
{
BstNode **parent, ***p;
parent=NULL;
p=&root;
while((**p!=NULL) && (key!=(**p)->data))
{
parent=&(**p);
if((**p)->data < key) *p=&(**p)->right;
else *p=&(**p)->left;
}
if((**p)==NULL)
{
cout << "no such element! " <<endl;
return;
}
if(((**p)->right)==NULL && (**p)->left==NULL)
{
if((**p)==*root)
{
*root=NULL;
return;
}
if((*parent)->right==(**p))
(*parent)->right = NULL;
else (*parent)->left = NULL;
return;
}
if(((**p)->right)==NULL )
{
if((*parent)->right== (**p))
(*parent)->right = (**p)->left;
else
(*parent)->left = (**p)->left;
return;
}
if(((**p)->left)==NULL )
{
if((*parent)->right==(**p))
(*parent)->right = (**p)->right;
else
(*parent)->left = (**p)->right;
return;
}
}
int main()
{
BstNode* root = NULL;
Insert(&root,2);
/* ... */
Remove(&root,2);
}
I believe that there's something wrong with "parent", because root has no parent. However, I have no idea how to find a way round this problem.
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);
}
}
Whenever I insert the tree data in, and try to delete them, it works for all except the last remaining node. Or even if I insert only one node and try to delete it, it doesn't, it continues displaying the node. I tried debugging the code, but seems clueless. Please help!
void Remove(node *Current, int key) {
node *prev = new node;
if(Current == NULL)
cout << "List is empty.\n";
else {
while(Current != NULL) {
if(Current->value == key)
break;
else {
prev = Current;
if(Current->value >key)
Current = Current->left;
else
Current = Current->right;
}
}
if(Current->left == NULL && Current->right == NULL) {
if(prev->left == Current)
prev->left = NULL;
else
prev->right = NULL;
delete(Current);
}
else if(Current->left != NULL && Current->right == NULL) {
if(prev->left == Current)
prev->left = Current->left;
else
prev->right = Current->left;
delete(Current);
}
else if(Current->left == NULL && Current->right != NULL) {
if(prev->left == Current)
prev->left = Current->right;
else
prev->right = Current->right;
delete(Current);
}
else if(Current->left != NULL && Current->right != NULL) {
node *temp = Current->right;
if(temp->left == NULL && temp->right == NULL) {
Current->value = temp->value;
delete(temp);
Current->right = NULL;
}
//////////////////////////////////////
else if(Current->right->left != NULL)
{
node *left_current = Current->right;
node *left_current_prev = Current->right->left;
while(left_current->left != NULL)
{
left_current_prev = left_current;
left_current = left_current->left;
}
Current->value = left_current->value;
delete(left_current);
left_current_prev->left = NULL;
}
//////////////////////////////////////
else
{
node *temp;
temp = Current->right;
Current->value = temp->value;
Current->right = temp->right;
delete(temp);
}
//////////////////////////////////////
}
}
}
if I insert only one node and try to delete it, it doesn't, it
continues displaying the node
Every tree has a base, a pointer to the first node of the tree.
tree base --> Current node --> left node ...
--> right node ,,,
This base pointer appears to be available to the caller of function Remove,
... code leading to
Remove (tree base->Current, key)
... subsequent code
but you did not give Remove access to the tree base to modify it.
In other words, Remove() (probably) deletes Current, but tree base still points to where Current was when Remove() returns.
You probably need to review what happens when the key does not match the value in the last node.
This is my code for an insertion-sort, sorting via the cstring member of the node. The current code only inserts before the head. The code encapsulated in comments is the sorted insertion I am trying to make work. I'm thinking I have to use a predecessor and successor pointer, but maybe it's the comparison that is confusing me. Any help would be appreciated. Thanks!
#include <iostream>
#include "groclist.h"
void insert_item(Grocery_Item_Ptr &head, int quantity, const char name[])
{
bool exists = false;
bool done = false;
Grocery_Item_Ptr temp = NULL;
Grocery_Item_Ptr current = NULL;
Grocery_Item_Ptr pred = NULL;
Grocery_Item_Ptr succ = NULL;
if (head == NULL) {
head = new Grocery_Item;
head->quantity = quantity;
strncpy(head->name, name, MAX_ITEM_NAME_LEN);
head->next = NULL;
return;
}
else {
current = head;
while (current != NULL) {
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) == 0) {
current->quantity += quantity;
exists = true;
}
current = current->next;
}
if (exists) {
current = NULL;
return;
}
else {
current = head;
}
if (!exists) {
temp = new Grocery_Item;
temp->quantity = quantity;
strncpy(temp->name, name, MAX_ITEM_NAME_LEN);
/*
while (!done || current != NULL) {
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) < 0) {
pred = current;
succ = current->next;
current->next = temp;
temp->next = succ;
done = true;
}
if (!done) {
current = current->next;
}
}
*/
temp->next = head;
head = temp;
temp = NULL;
}
}
return;
}
One thing you are missing is keeping a reference to the predecessor while searching. This is necessary in order to keep the chain intact.
Here is a draft that should work (currently untested!):
while (!done || current != NULL)
{
//If we found the place to insert
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) < 0)
{
//If the place to insert was at head
if(pred == NULL)
{
//The new node becomes the head
head = temp;
}
else
{
//Set the previous nodes next to point at this node.
pred->next = temp;
}
//Always set the node to be inserted's next
//pointing to the node we should be inserted before
temp->next = current;
done = true;
}
if (!done)
{
//No match, keep looking but keep an updated pred pointer
pred = current;
current = current->next;
}
}
It's just pseudocode, but maybe it helps:
if(head == NULl)
{
//make newnode as head
}
if(head.name == new name)
{
//update quantity
}
if(head.name <new name)
{
//insert newnode before head
//make newnode as head
}
if (new name > head.name)
{
current = head;
succ = current.next;
while (succ && new name <succ.name)
{
curent = succ;
succ = succ.next
}
if(succ = NULL)
current->next = newnode
else
if new name = succ->name
update quantity
else
curent->next = newnode
newnode->next = succ;
}
I appreciate your input guys, if only for having me think about it in different ways. However my result is quite different, and I must truly thank my whiteboard.
if (strncmp(name, head->name, MAX_ITEM_NAME_LEN) < 0) {
temp->next = head;
head = temp;
temp = NULL;
}
else {
pred = head;
current = head->next;
do {
if (strncmp(name, current->name, MAX_ITEM_NAME_LEN) < 0) {
pred->next = temp;
temp->next = current;
done = true;
}
else if (current->next == NULL) {
current->next = temp;
done = true;
}
else {
pred = current;
current = current->next;
}
if (done) {
pred = NULL;
current = NULL;
}
} while (!done && current != NULL);
}