I am trying to delete the minimum node from a BST. But I get a seg fault.
To my understanding, minimum node will have no children, hence deleting it would not result in desserted leftover subtree. I am unsure on how to remove a node from a BST, I saw some solution that uses free() instead of delete. Where did I go wrong?
Source code for testing: https://onlinegdb.com/kiOZQee3w
***Added some code in editing
void delete_min()
{
Node* min_node = min();
Node* min_parent = min_node->parent; //Added this
if(!root)
{
return;
}
// If min is root (Added this)
if(!root->left)
{
auto tmp = root;
root = root->right;
delete tmp;
return;
}
min_parent->left = min_node->right; //Added this
delete min_node;
--size;
}
Node* min()
{
if(root == nullptr)
{
return root;
}
else
{
return min(root);
}
}
Node* min(Node* node)
{
while(node->left != nullptr)
{
node = node->left;
}
return node;
}
At very first your assumption that the minimum node doesn't have children is wrong; it doesn't have a left child, but it might have a right child; consider the most simple case of the root node and one single child that's greater than:
1
\
2
Then for removing a node you cannot just only delete it, but you need to adjust it's parent's left pointer, too – or the root pointer, if the root is the minimum node. You can simply set it to the minimum's right child (can either of another node or a null pointer).
Update according to the code code provided on online GDB (this version is not matching the version in the question!):
Node* min_node = min();
if(min_node->right != nullptr)
{
min_node->parent->left = min_node->right;
}
delete min_node;
You need to update the parent's left child unconditionally – if there's no grandchild, you'll just copy the null pointer that way, which is fine, as there won't be a right child any more anyway (the only one gets deleted).
But if there's a grandchild you need to update its parent (which otherwise would remain pointing to the deleted node, thus get dangling!):
Node* min_node = min();
min_node->parent->left = min_node->right;
if(min_node->right)
{
min_node->right->parent = min_node->parent;
}
delete min_node;
For this, though, you need the parent node available, too, thus you need to adjust the lookup of the minimum appropriately unless your nodes contain a link to their respective parent, too. Assuming this not being the case then your iteration might look as follows:
void deleteMin()
{
// special handling: empty tree
if(!root)
{
return;
}
// special handling: minimum is root
if(!root->left)
{
auto tmp = root;
root = root->right;
delete tmp;
return;
}
// now look for the minimum as you had already, but keep
// track of the parent node as well!
auto parent = root;
child = root->left;
while(child->left)
{
parent = child;
child = child->left;
}
// OK, minimum found; essential step: adjust its parent!
parent->left = child->right; // works for both a child available or not
// now can safely delete:
delete child;
}