Reputation: 47
I have this function for deleting a node in a binary search tree which seems to be working EXCEPT in the case where I ask it to delete the root node. It is supposed to take the right-most value on the left and replace the node with that; however, once that happens, the new root node's children pointers don't seem to point to the original root node's children. Code is as follows:
bool delete_node(Node*& root, TYPE data) {
Node* toDelete;
Node* parent;
// This function is defined appropriately elsewhere, and finds the target to be deleted
toDelete = find(data, root);
if (!toDelete) {
return false;
}
// This function is defined appropriately elsewhere, and finds the parent of the node to be deleted
parent = find_parent(root, toDelete);
// Other cases left out because they work
// If the target node has two children:
if (toDelete->left && toDelete->right)
{
// find rightmost child on left that is a leaf
Node *replacement = toDelete->left;
while (replacement->right)
{
replacement = replacement->right;
}
// set the target node's data
toDelete->data = replacement->data;
if (parent)
{
if ( parent->data < toDelete->data )
{
parent->right = replacement;
} else
{
parent->left = replacement;
}
} else
{
// if node has no parents, then it is the root and should be replaced with replacement
// This line here is what seems to be causing my trouble...I think
root = replacement;
}
parent = find_parent(toDelete, replacement);
if (parent)
{
if (parent->left == replacement)
parent->left = NULL;
else
parent->right = NULL;
}
delete toDelete;
return true;
}
}
Thanks in advance!
Upvotes: 3
Views: 20929
Reputation: 4839
This is what I did to make it work. Just check if the node is the root node, and if so, set the new root. Below is the working code I have. The three places marked by asterisks is what I added to make it work. All the other lines of code is just standard textbook theory.
inline NamesBinaryTree::Node* NamesBinaryTree::Node::removeNode (Node*& node, const Female* female, stringComparisonFunction s) { // Taken from p.253 of Alex Allain's "Jumping Into C++".
if (!node)
return nullptr;
if (node->femaleInfo.first == female->getName()) {
if (!node->left) { // i.e. node has either one child or zero children.
Node* rightNode = node->right;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(rightNode); // Tested to work correctly. Note that we cannot call 'delete node;', since that will delete the very root that we are setting!
else
delete node;
return rightNode; // This will return nullptr if node->right is also nullptr, which is what we would want to do anyway since that would mean that node has zero children.
}
if (!node->right) { // i.e. node has exactly one child, namely its left child, in which case return that left child.
Node* leftNode = node->left;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(leftNode);
else
delete node;
return leftNode; // This will never be nullptr, else the previous if condition would have been met instead.
}
Node* maxNode = findMaxNode(node->left); // node has two children, so it shall be replaced by the largest valued node in its left subtree.
maxNode->left = removeMaxNode(node->left, maxNode); // Note that maxNode->left = node->left is not enough because without actually removing maxNode, the node that was pointing to maxNode will now be pointing to maxNode in its new position (and the subtree under it), and the subtree that was under maxNode will now be gone.
maxNode->right = node->right;
if (node->isRoot()) // ***
namesBinaryTree.setRoot(maxNode); // Tested to work correctly.
else
delete node;
return maxNode;
}
else {
const int result = (*s)(female->getName(), node->femaleInfo.first);
if (result < 0)
node->left = removeNode(node->left, female, s); // This assignment can only work if node is passed by reference (hence the parameter Node*& node), at least this is what "C++ Essentials" did in their solution, p.247.
else // Don't use 'else if (result > 0)'. Let the equality case be covered here too (just as in NamesBinaryTree::Node::insertNode).
node->right = removeNode(node->right, female, s); // Again, this assignment can only work if node is passed by reference (hence the parameter Node*& node).
}
return node; // So if node->femaleInfo.first != female->getName(), then the same node is returned, which means that the two assignment lines above don't change any values.
}
Upvotes: 0
Reputation: 47
what I ended coming up with was this: keep track of the parent node that is one above the node that replaces the node to be deleted. there will then be 2 cases to consider: the parent is the node to be deleted and parent is not the node to be deleted. by replacing the appropriate parts of the tree at the right case, the structure and invariants of the tree remained ok and the node to be deleted was successfully deleted. technically, it would be the data at the node to be deleted.
else if (toDelete->left != NULL && toDelete->right != NULL) {
// find rightmost child on left that is a leaf
Node* replacement = toDelete->left;
parent = toDelete;
// parent is now the parent of the replacement
while ( replacement->right ) {
parent = replacement;
replacement = replacement->right;
} // By the end, parent will be the node one above replacement
toDelete->key = replacement->key;
if (parent == target)
parent->left = replacement->left;
else
parent->right = replacement->left;
delete replacement;
return true;
}
Upvotes: 1