Custom BST deletion (C++) - c++

I'm implementing a custom BST which stores data in leaves and each node represents its subtree's smallest value. The left nodes store the higher values and the right nodes store the lower values.
I then delete the data by deleting the leaves and updating the internal nodes, but somehow my deletion could not work.
Here is my code, hope you can point out something wrong with it. Thank you very much.
inline BstNode* BstDelete(BstNode* root, rectangle del){
if (root == NULL) return root;
else if (del > root->data){
root->left = BstDelete(root->left,del);
if(root->left == NULL) root->data = root->right->data;
root->data = root->left->data;
}
else if(del < root->data){
root->right = BstDelete(root->right,del);
if (root->right == NULL) root->data = root->left->data;
root->data = root->right->data;
}
else {
//found
//Case1: No Child
if (root -> left == NULL && root->right == NULL){
delete root;
root = NULL;
}
//One child
else if (root->left == NULL){
root->right = BstDelete(root->right, del);
if(root->right ==NULL) root = root->right;
else root->data = root->right->data;
}
else if (root->right == NULL){
root->left = BstDelete(root->left,del);
if(root->left == NULL) root = root->left;
else root->data = root->left->data;
}
// 2 children
else {
root->right = BstDelete(root->right, del);
if (root->right == NULL) root->data = root->left->data;
else root->data = root->right->data;
}
}
return root;}

Related

Exception thrown: read access violation.during BST Deletion for many elements

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.

What are the problems in the following code?

I have tow code about the the question Binary Tree Pruning.
this is a wrong code
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
if(root == NULL)
return NULL;
if((root->left = pruneTree(root->left)) == NULL &&
(root->right = pruneTree(root->right)) == NULL){
if(root->val == 0){
delete root;
return NULL;
}
}
return root;
}
};
this is my passed code
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
if(root == NULL)
return NULL;
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
if(root->left == NULL && root->right == NULL){
if(root->val == 0){
delete root;
return NULL;
}
}
return root;
}
};
I want to know what cause the difference between the two programs
In the second code, it is guaranteed that both pruneTree(root->left) and pruneTree(root->right) are called, because those are two separate expressions.
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
In the first code you have:
(root->left = pruneTree(root->left)) == NULL &&
(root->right = pruneTree(root->right)) == NULL
The difference here is that pruneTree(root->left) and pruneTree(root->right) are in one expression, so they might (and this case the do) depend on each other.
If (root->left = pruneTree(root->left)) == NULL evaluates to false then the parte after the && does not need to be evaluated, because the complete expression can't become true anymore.

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<>)

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!