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.
|
* 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);
|
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,
|
void vieter_tree_node_replace_with_child(vieter_tree_node *to_replace,
|
||||||
vieter_tree_node *replacement) {
|
vieter_tree_node *replacement) {
|
||||||
to_replace->key = replacement->key;
|
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;
|
*out = target->data;
|
||||||
|
|
||||||
if (target->children[0] == NULL && target->children[1] == NULL) {
|
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 {
|
|
||||||
vieter_tree_node *replacement = target->children[1];
|
vieter_tree_node *replacement = target->children[1];
|
||||||
|
|
||||||
while (replacement->children[0] != NULL) {
|
while (replacement->children[0] != NULL) {
|
||||||
replacement = replacement->children[0];
|
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->key = replacement->key;
|
||||||
target->data = replacement->data;
|
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;
|
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,
|
void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key,
|
||||||
vieter_tree_node *child);
|
vieter_tree_node *child);
|
||||||
void vieter_tree_node_set_children(vieter_tree_node *parent, vieter_tree_node **children);
|
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);
|
bool vieter_tree_node_validate(vieter_tree_node *node, uint64_t passed_black_nodes, uint64_t expected_black_nodes);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue