forked from vieter-v/libvieter
feat(tree): start of balanced removal
parent
b74a4e9326
commit
1d458c68a4
|
@ -124,4 +124,25 @@ void vieter_tree_node_balance_after_insert(vieter_tree_node *node) {
|
|||
}
|
||||
}
|
||||
|
||||
void vieter_tree_node_remove_balanced(vieter_tree_node *node) {}
|
||||
void vieter_tree_node_remove_balanced(vieter_tree_node *node) {
|
||||
// A red node can only have 0 or 2 children. The node we receive only has
|
||||
// one child at most, so we know if it's red that it doesn't have any
|
||||
// children. A black node that has a single (right) child can be replaced by
|
||||
// this child, granted it becomes black as well. Either way, the node can be
|
||||
// replaced by its right child (even if it's NULL).
|
||||
if (!vieter_tree_node_get(node, vieter_tree_node_black) ||
|
||||
node->children[1] != NULL) {
|
||||
vieter_tree_node_set_child(
|
||||
node->parent, node->children[1],
|
||||
vieter_tree_node_get(node, vieter_tree_node_right));
|
||||
|
||||
if (node->children[1] != NULL)
|
||||
vieter_tree_node_set(node->children[1], vieter_tree_node_black, true);
|
||||
|
||||
vieter_tree_node_free(node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The complicated case is when we want to remove a black leaf
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ void vieter_tree_node_balance_after_insert(vieter_tree_node *node);
|
|||
/*
|
||||
* Remove the given node, ensuring the tree remains a valid red-black tree.
|
||||
*
|
||||
* @param node node to remove. This node should have at least one NULL child.
|
||||
* @param node node to remove. This should have at most a single child, namely
|
||||
* the right one.
|
||||
*/
|
||||
void vieter_tree_node_remove_balanced(vieter_tree_node *node);
|
||||
|
||||
|
|
|
@ -36,6 +36,16 @@ void vieter_tree_node_set_children(vieter_tree_node *parent,
|
|||
}
|
||||
}
|
||||
|
||||
void vieter_tree_node_set_child(vieter_tree_node *parent,
|
||||
vieter_tree_node *child, bool right) {
|
||||
parent->children[right] = child;
|
||||
|
||||
if (child != NULL) {
|
||||
child->parent = parent;
|
||||
vieter_tree_node_set(child, vieter_tree_node_right, right);
|
||||
}
|
||||
}
|
||||
|
||||
void vieter_tree_node_replace_with_child(vieter_tree_node *to_replace,
|
||||
vieter_tree_node *replacement) {
|
||||
to_replace->key = replacement->key;
|
||||
|
@ -110,40 +120,19 @@ vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *root,
|
|||
|
||||
*out = target->data;
|
||||
|
||||
if (target->children[0] == NULL && target->children[1] == NULL) {
|
||||
vieter_tree_node_add_child(target->parent, target->key, NULL);
|
||||
|
||||
vieter_tree_node_free(target);
|
||||
} else if ((target->children[0] == NULL) ^ (target->children[1] == NULL)) {
|
||||
vieter_tree_node *child =
|
||||
target->children[0] != NULL ? target->children[0] : target->children[1];
|
||||
|
||||
if (target->parent != NULL) {
|
||||
vieter_tree_node_add_child(target->parent, child->key, child);
|
||||
vieter_tree_node_free(target);
|
||||
} else {
|
||||
vieter_tree_node_replace_with_child(target, child);
|
||||
vieter_tree_node_free(child);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (target->children[0] != NULL && target->children[1] != NULL) {
|
||||
vieter_tree_node *replacement = target->children[1];
|
||||
|
||||
while (replacement->children[0] != NULL) {
|
||||
replacement = replacement->children[0];
|
||||
}
|
||||
|
||||
// We use replacement->key here because the right child can be NULL, so
|
||||
// reading its key isn't safe. Using replacement->key however, the child
|
||||
// will still get placed into the right location because of how binary
|
||||
// trees work.
|
||||
vieter_tree_node_add_child(replacement->parent, replacement->key,
|
||||
replacement->children[1]);
|
||||
|
||||
target->key = replacement->key;
|
||||
target->data = replacement->data;
|
||||
|
||||
vieter_tree_node_free(replacement);
|
||||
vieter_tree_node_remove_balanced(replacement);
|
||||
} else {
|
||||
vieter_tree_node_remove_balanced(target);
|
||||
}
|
||||
|
||||
return vieter_tree_ok;
|
||||
|
|
|
@ -43,6 +43,7 @@ bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag);
|
|||
void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key,
|
||||
vieter_tree_node *child);
|
||||
void vieter_tree_node_set_children(vieter_tree_node *parent, vieter_tree_node **children);
|
||||
void vieter_tree_node_set_child(vieter_tree_node *parent, vieter_tree_node *child, bool right);
|
||||
|
||||
bool vieter_tree_node_validate(vieter_tree_node *node, uint64_t passed_black_nodes, uint64_t expected_black_nodes);
|
||||
|
||||
|
|
Loading…
Reference in New Issue