so am having problems with the exception during deletion(Exception thrown: read access violation.
parent was 0x158398.)like that sometimes are different numbers etc and always its about parent object/pointer, my code is working without any errors,exceptions till 100k objects then sometimes works sometimes not, for 1 milion is not even working anymore.If anybody could help out would be great. under post am posting code:
Node Class:
template <class T>
class Node {
public:
T data;
Node<T>* Left = NULL;
Node<T>* Right = NULL;
};
the code for finding min of right subtree:
Node<T>* findMin(Node<T>* node)
{
while (node->Left != NULL)
node = node->Left;
return node;
}
code for Deletion:
void Delete(Node<T>*& node) {
if (node == NULL)
return;
Node<T>* parent = findParentForDelete(this->root, node);
Node<T>* temp = NULL;
//leafs
if (node->Left == NULL && node->Right == NULL) {
if (node == root) {
delete root;
root = NULL;
return;
}
else {
if (parent->Left == node) //line with exception
parent->Left = NULL;
else
parent->Right = NULL;
delete node;
node = NULL;
return;
}
}
//1 child left not null
else if (node->Left != NULL && node->Right == NULL)
{
if (node == root) {
temp = root->Left;
delete root;
root = NULL;
root = temp;
return;
}
else {
if (parent->Left == node)
parent->Left = node->Left;
else
parent->Right = node->Left;
delete node;
node = NULL;
return;
}
}
//1 child Right not null
else if (node->Left == NULL && node->Right != NULL)
{
if (node == root) {
temp = root->Right;
delete root;
root = NULL;
root = temp;
return;
}
else {
if (parent->Left == node)
parent->Left = node->Right;
else
parent->Right = node->Right;
delete node;
node = NULL;
return;
}
}
//2 childs
else if (node->Left != NULL && node->Right != NULL)
{
temp = findMin(node->Right);
T data = temp->data;
Delete(temp);
node->data = data;
}
}
finding parent:
Node<T>* findParentForDelete(Node<T>* node, Node<T>*& nodeToFind)
{
if (node == NULL)
return NULL;
if (node->Left == NULL && node->Right == NULL)
return NULL;
if ((node->Left != NULL && node->Left == nodeToFind)
|| (node->Right != NULL && node->Right == nodeToFind))
return node;
if (node->data->age > nodeToFind->data->age)
return findParentForDelete(node->Left, nodeToFind);
if (node->data->age < nodeToFind->data->age)
return findParentForDelete(node->Right, nodeToFind);
}
findParentForDelete does not always return a value.
It will not return a value if the node you're looking for has an age that is the same as a different node in the tree, so the value returned to the caller will be a garbage value.
If you increase the warning level when you compile, most compilers will issue a warning for this.
Related
I have written a code for insertion in Binary Search Tree and its traversal.
class node
{
public:
int data;
node *left;
node *right;
};
node* createNode(int value)
{
node *temp = new node;
temp->data = value;
temp->left = NULL;
temp->right = NULL;
return temp;
}
node *start = NULL;
void insertNode(int val)
{
if (start == NULL)
{
start = createNode(val);
return;
}
node *temp = start;
while ((temp->left != NULL) && (temp->right != NULL))
{
if (val < temp->data)
{
temp = temp->left;
}
else if (val > temp->data)
{
temp = temp->right;
}
else
{
cout << "Already exists in tree\n";
return;
}
}
if (val < temp->data)
{
temp->left = createNode(val);
return;
}
else
{
temp->right = createNode(val);
return;
}
}
void inorder(node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d \n", root->data);
inorder(root->right);
}
}
It does not work fine on some test cases.
For example, if insert 15, 25 and then 35, and then traverse the tree, it only prints 15 and 25.
I am not able to find out the problem in the code. What is the issue with my insertion logic?
Let's go through the behavior -
you insert the 15. if (start == NULL)
this check creates the start node. Now there is a start node with value 15 and left and right as NULL.
you insert 25. (temp->left != NULL) && (temp->right != NULL)
this turns out to be false.
(val < temp->data) this check creates a right node.
you insert 35. (temp->left != NULL) && (temp->right != NULL)
still turns out to be false.
(val < temp->data) this check creates a right node (replacing the current right node). Which is not right.
You need to correct the while loop condition here.
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 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.
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!