Removing an element from BST (pointer error) - c++

So I have my own implementation on BST. Now I need to implement remove_value function, which would remove a node with that value from my tree. I have this simple code:
void binary_tree::remove_value(int value)
{
if (!this->exists(value)) return; //if value doesnt exist - return
nodeBST* current = root;
nodeBST* prev = nullptr;
bool left = true;
while (true)
{
if (current->value == value) // when we find it
{
if (current->right == nullptr && current->left == nullptr) // 0 children
{
delete current;
this->n--;
if (left) prev->left = nullptr;
else prev->right = nullptr;
//even tried delete current here
return;
}
else if (current->right == nullptr && current->left != nullptr) // 1 lewe dziecko
{
if (left) prev->left == current->left;
else prev->right == current->left;
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left == nullptr) // 1 prawe dziecko dziecko
{
if (left) prev->left == current->right;
else prev->right == current->right;
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left != nullptr) // dwoje dzieci
{
nodeBST* tempNode = findMin(current);
current->value = tempNode->value;
remove_node(current, prev, left);
}
}
else if (current->value > value)
{
prev = current;
left = true;
current = current->left;
}
else
{
prev = current;
left = false;
current = current->right;
}
}
}
I know its kinda mess, so I will tell you what it does. The bottom part is looping through the tree. If the the value we are searching is bigger that the current node value, the previous becomes current, current becomes current->right and left = false. The opposite, when its smaller. Now look that the first if after current->value == value - this is the code which should execute for 0 children. Now, it does delete the current node, but I have a problem.
I have a printing function, which takes a whole tree, and prints it. And it crashes with some pointer error. I checked. When I delete current it sets prev->left or prev->right (depending on left value) to like 0xdddddddd, no matter if I delete after assigning prev-> or before. I even tried to delete prev->right/left and then assign nullptr but still the same happens. How can I make it delete the node, but still be able to assign nullptr to right or left property of prev node?
#Edit:
This code fails on line with print(:
void binary_tree::print(std::string sp, std::string sn, nodeBST* v)
{
if (this->is_empty()) return;
std::string s;
if (v)
{
s = sp;
if (sn == cr) s[s.length() - 2] = ' ';
print(s + cp, cr, v->right);
s = s.substr(0, sp.length() - 2);
std::cout << s << sn << v->value << std::endl;
s = sp;
if (sn == cl) s[s.length() - 2] = ' ';
print(s + cp, cl, v->left);
}
}
The exception is something like (I am translating from my language) that there was unwanted read from memory, and that the v was 0xddddd

So there was a bug inside if (current->right == nullptr && current->left == nullptr). This code is working:
void binary_tree::remove_value(int value)
{
if (!this->exists(value)) return; //if value doesnt exist - return
nodeBST* current = root;
nodeBST* prev = nullptr;
bool left = true;
while (true)
{
if (current->value == value) // when we find it
{
if (current->right == nullptr && current->left == nullptr) // 0 children
{
delete current;
this->n--;
if(prev!=nullptr) {
if (left) prev->left = nullptr;
else prev->right = nullptr;
}
//even tried delete current here
return;
}
else if (current->right == nullptr && current->left != nullptr) // 1 lewe dziecko
{
if(prev!=nullptr) {
if (left) prev->left == current->left;
else prev->right == current->left;}
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left == nullptr) // 1 prawe dziecko dziecko
{
if(prev!=nullptr) {
if (left) prev->left == current->right;
else prev->right == current->right;}
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left != nullptr) // dwoje dzieci
{
nodeBST* tempNode = findMin(current);
current->value = tempNode->value;
remove_node(current, prev, left);
}
}
else if (current->value > value)
{
prev = current;
left = true;
current = current->left;
}
else
{
prev = current;
left = false;
current = current->right;
}
}
}

Related

Binary search tree code giving out of resources error

I was trying to create a binary search tree with insert, search and remove functions but when run, the program throwing an error " Killed exit status 137 -- Out Of Resources --" ,
#include <vector>
using namespace std;
class BST
{
public:
int value;
BST *left;
BST *right;
BST(int val)
{
value = val;
left = nullptr;
right = nullptr;
}
BST& insert(int val)
{
BST *current = this;
while (current != nullptr)
{
if (val < current->value)
{
if (current->left == nullptr)
{
current->left = new BST(val);
break;
}
else
current = current->left;
}
if (val > current->value)
{
if (current->right == nullptr)
{
current->right = new BST(val);
break;
}
else
current = current->right;
}
}
return *this;
}
bool contains(int val)
{
BST *current = this;
while (current != nullptr)
{
if (val < current->value)
{
current = current->left;
}
else if (val > current->value)
{
current = current->right;
}
else if (val == current->value)
return true;
//else if(current ==nullptr)
//return false;
}
return false;
}
BST& remove(int val)
{
BST *current = this;
BST *parent = nullptr;
while (current != nullptr)
{
if (val < current->value)
{
parent = current;
current = current->left;
}
if (val > current->value)
{
parent = current;
current = current->right;
}
if (val == current->value)
{
if (current->left != nullptr && current->right != nullptr)
{
fnd(current->right);
}
else if (parent == nullptr)
{
if (current->left != nullptr)
{
current->value = current->left->value;
current->right = current->left->right;
current->left = current->left->left;
}
else if (current->right != nullptr)
{
current->value = current->right->value;
current->left = current->right->left;
current->right = current->right->right;
}
else
current = nullptr;
}
else if (parent->left == current)
{
if (current->left != nullptr)
{
parent->left = current->left;
}
else
{
parent->left = current->right;
}
}
else if (parent->right == current)
{
if (current->left != nullptr)
{
parent->right = current->left;
}
else
{
parent->right = current->right;
}
}
break;
}
}
return *this;
}
void fnd(BST *current)
{
BST *trav = current;
BST *parent;
while (trav->left != nullptr)
{
parent = trav;
trav = trav->left;
}
current->value = trav->value;
parent->left = nullptr;
}
};

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

Binary Search Tree can't delete first 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.

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 Deletion 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.