Red Black Tree - deletion
I've implemented delete function for RBT (basing on Cormen), it looks like it works but test for deletion + printing tree in preorder gives me wrong answer. I spent few hours looking what may be wrong but couldn't find anything...
Here's func to print tree in preorder:
void print_out(rbt_node *root, rbt_node *NIL)
{
if(root != NIL)
{
printf("%d %s ", root->key, root->data.c_str());
if(root->color == BLACK)
printf("black ");
else
printf("red ");
if(root->parent != NIL)
printf("%d ",root->parent->key);
else
printf("- ");
if(root->left != NIL)
printf("%d ",root->left->key);
else
printf("- ");
if(root->right != NIL)
printf("%d ",root->right->key);
else
printf("- ");
printf("\n");
print_out(root->left, NIL);
if(root->right != NIL)
{
print_out(root->right, NIL);
}
}
}
Here is rest of important stuff for deletion:
rbt_node *NIL = new rbt_node;
NIL->color = BLACK;
NIL->left = NIL->parent = NIL->right = NIL;
rbt_node *tree_minimum(rbt_node *node, rbt_node *NIL)
{
while(node->left != NIL)
node = node->left;
return node;
}
rbt_node *tree_succesor(rbt_node *node, rbt_node *NIL)
{
if(node->right != NIL)
return tree_minimum(node->right, NIL);
rbt_node *helper = node->parent;
while(helper != NIL && node == helper->right)
{
node = helper;
helper = helper->parent;
}
return helper;
}
void delete_fixup(rbt_node *&root, rbt_node *&target, rbt_node *NIL)
{
rbt_node *helper = NIL;
while(target != root && target->color == BLACK)
{
if(target == target->parent->left)
{
helper = target->parent->right;
if(helper->color == RED)
{
helper->color = BLACK;
target->parent->color = RED;
left_rotate(root, target->parent, NIL);
helper = target->parent->right;
}
if(helper->left->color == BLACK && helper->right->color == BLACK)
{
helper->color = RED;
target = target->parent;
}
else if(helper->right->color== BLACK)
{
helper->left->color = BLACK;
helper->color = RED;
right_rotate(root, helper, NIL);
helper = target->parent->right;
}
else
{
helper->color = target->parent->color;
target->parent->color = BLACK;
helper->right->color = BLACK;
left_rotate(root, target->parent, NIL);
target = root;
}
}
else
{
helper = target->parent->left;
if(helper->color == RED)
{
helper->color = BLACK;
target->parent->color = RED;
right_rotate(root, target->parent, NIL);
helper = target->parent->left;
}
if(helper->right->color == BLACK && helper->left->color == BLACK)
{
helper->color = RED;
target = target->parent;
}
else if(helper->left->color== BLACK)
{
helper->right->color = BLACK;
helper->color = RED;
left_rotate(root, helper, NIL);
helper = target->parent->left;
}
else
{
helper->color = target->parent->color;
target->parent->color = BLACK;
helper->left->color = BLACK;
right_rotate(root, target->parent, NIL);
target = root;
}
}
}
target->color =开发者_Go百科 BLACK;
}
void rbt_delete(rbt_node *&root, int key, rbt_node *NIL)
{
rbt_node *victim = to_delete(root, key, NIL);
if(victim != NIL)
{
rbt_node *help_one = NIL;
rbt_node *help_two = NIL;
if(victim->left == NIL || victim->right == NIL)
help_one = victim;
else
help_one = tree_succesor(victim, NIL);
if(help_one->left != NIL)
help_two = help_one->left;
else
help_two = help_one->right;
help_two->parent = help_one->parent;
if(help_one->parent == NIL)
root = help_two;
else if(help_one == help_one->parent->left)
help_one->parent->left = help_two;
else
help_two->parent->right = help_two;
if(help_one != victim)
{
victim->key = help_one->key;
victim->data = help_one->data;
}
if(help_one->color == BLACK)
delete_fixup(root, help_two, NIL);
}
root->color = BLACK;
}
At least IMO, your print_out
isn't really working the way it should. The specific problem is that it's trying to (directly) print out data for child nodes.
When you're dealing with a binary tree (of any sort -- unbalanced, AVL, RB, etc.) traversal will normally look roughly like this:
void print_out(node *current_node) {
if current_node != NIL {
show_data(current_node);
print_out(current_node->left);
print_out(current_node->right);
}
}
As is, that's pre-order; post-order or inorder is just a matter of rearranging the print_data
compared to the recursive calls to print_out
(for post-order it comes after them, for inorder between them).
In particular, however, print_out should not have anything to do with the left or right sub-trees, other than by passing them as parameters in a recursive call. It also shouldn't normally check whether they're NIL/NULL either -- it should just make the recursive call, and let the if (current_node != NIL)
handle in the recursive call deal with the possibility that we've hit a leaf node.
Call me lazy if you will, but that's about as much as I'm willing to examine without at least some guidance about what sort of problem I'm looking for, and at least as reasonable assurance that it's the right place to look. It would be helpful (for example) if you showed that you can insert a few nodes, and get the expected structure, then show what goes wrong when you delete a node. Is the node still there? Are other nodes getting lost? Are all the nodes right, but the balance is wrong? If so, what's going wrong with the balance?
精彩评论