Commit 8ad9ba34 authored by Chris Müller's avatar Chris Müller

lib: add removal for maps (red-black trees).

parent 00696d87
......@@ -32,7 +32,7 @@ size_t cry_map_size(struct CryMap* map);
pointer cry_map_lookup(struct CryMap* map, const_pointer key);
return_code cry_map_insert(struct CryMap* map, const_pointer key, pointer value);
return_code cry_map_remove(struct CryMap* map, const_pointer key, cry_free_funptr key_free, cry_free_funptr value_free);
pointer cry_map_remove(struct CryMap* map, const_pointer key, cry_free_funptr key_free);
void cry_map_dump_debug(struct CryMap* map);
......
......@@ -38,9 +38,6 @@ struct RBNode {
#define RB_GRAND_PARENT(node) node->parent->parent
struct CryMap {
struct RBNode* root;
cry_ordering_funptr compare;
......@@ -75,11 +72,31 @@ rb_tree_dump_with_strings(struct RBNode* node, cry_ordering_funptr compare, size
printf("null (BLACK)\n");
else {
if(compare == cry_cast(cry_ordering_funptr, strcmp))
printf("%s (%s)\n", cry_cast(const char*, node->key), (node->color == BLACK) ? "BLACK" : "RED");
if(RB_PARENT(node) != 0)
printf("%s (%s, parent %s)\n", cry_cast(const char*, node->key),
(node->color == BLACK) ? "BLACK" : "RED",
cry_cast(const char*, RB_PARENT(node)->key));
else
printf("%s (%s, root)\n", cry_cast(const char*, node->key),
(node->color == BLACK) ? "BLACK" : "RED");
else if(compare == cry_int_compare)
printf("%d (%s)\n", *cry_cast(const int*, node->key), (node->color == BLACK) ? "BLACK" : "RED");
if(RB_PARENT(node) != 0)
printf("%d (%s, parent %d)\n", *cry_cast(const int*, node->key),
(node->color == BLACK) ? "BLACK" : "RED",
*cry_cast(const int*, RB_PARENT(node)->key));
else
printf("%d (%s, root)\n", *cry_cast(const int*, node->key),
(node->color == BLACK) ? "BLACK" : "RED");
else if(compare == cry_double_compare)
printf("%lf (%s)\n", *cry_cast(const double*, node->key), (node->color == BLACK) ? "BLACK" : "RED");
if(RB_PARENT(node) != 0)
printf("%lf (%s, parent %lf)\n", *cry_cast(const double*, node->key),
(node->color == BLACK) ? "BLACK" : "RED",
*cry_cast(const double*, RB_PARENT(node)->key));
else
printf("%lf (%s, root)\n", *cry_cast(const double*, node->key),
(node->color == BLACK) ? "BLACK" : "RED");
else
printf("%p (%s)\n", node->key, (node->color == BLACK) ? "BLACK" : "RED");
......@@ -175,6 +192,10 @@ rb_node_rotate_left(struct RBNode* node)
// correct parent hierarchy
node->parent = high;
high->parent = parent;
if(node->high != 0)
node->high->parent = node;
//node->high->parent = node;
if(parent != 0 && parent->low == node)
parent->low = high;
......@@ -195,11 +216,15 @@ rb_node_rotate_right(struct RBNode* node)
// switch left-node and its parent in a right-in-order rotation
node->low = low->high;
low->high = node;
// correct parent hierarchy
node->parent = low;
low->parent = parent;
if(node->low != 0)
node->low->parent = node;
//node->low->parent = node;
if(parent != 0 && parent->low == node)
parent->low = low;
else if(parent != 0 && parent->high == node)
......@@ -245,6 +270,7 @@ rb_remedy_double_red(struct CryMap* map, struct RBNode* node_z)
return;
if(RB_GRAND_PARENT(node_z)->low == 0 || RB_GRAND_PARENT(node_z)->high == 0 || RB_GRAND_PARENT(node_z)->low->color == BLACK || RB_GRAND_PARENT(node_z)->high->color == BLACK) {
// trinode restructering with single/multiple left- and right rotations
struct RBNode* node_v = rb_trinode_restructering(node_z);
node_v->color = BLACK;
......@@ -256,10 +282,11 @@ rb_remedy_double_red(struct CryMap* map, struct RBNode* node_z)
map->root = node_v;
} else {
// recoloring of nodes
RB_GRAND_PARENT(node_z)->low->color = BLACK;
RB_GRAND_PARENT(node_z)->high->color = BLACK;
if(map->root == RB_GRAND_PARENT(node_z))
if(RB_GRAND_PARENT(node_z)->parent == 0)
return;
RB_GRAND_PARENT(node_z)->color = RED;
......@@ -268,6 +295,70 @@ rb_remedy_double_red(struct CryMap* map, struct RBNode* node_z)
}
static void
rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode* node_r)
{
struct RBNode* sibling = (node_x->low == node_r) ? node_x->high : node_x->low;
struct RBNode* child = 0;
if(sibling == 0)
return;
enum RBNodeColor parent_color = node_x->color;
if(sibling->color == BLACK) {
// get red child of siblings if available
if(sibling->low != 0 && sibling->low->color == RED)
child = sibling->low;
else if(sibling->high != 0 && sibling->high->color == RED)
child = sibling->high;
if(child != 0) {
// Case 1: Restructering of siblings red child
child = rb_trinode_restructering(child);
child->color = parent_color;
if(node_r != 0)
node_r->color = BLACK;
child->low->color = BLACK;
child->high->color = BLACK;
while(child->parent != 0)
child = child->parent;
map->root = child;
} else {
// Case 2: Both siblings childs are black => Recoloring
if(node_r != 0)
node_r->color = BLACK;
sibling->color = RED;
if(node_x->color == RED)
node_x->color = BLACK;
else if(node_x->parent != 0) {
rb_remedy_double_black(map, RB_PARENT(node_x), node_x);
}
}
} else {
// Case 3: Sibling is red => Adjustment needed
if(node_x->high == sibling)
child = sibling->high;
else
child = sibling->low;
if(child != 0) {
child = rb_trinode_restructering(child);
sibling->color = BLACK;
node_x->color = RED;
while(child->parent != 0)
child = child->parent;
map->root = child;
rb_remedy_double_black(map, node_x, node_r);
}
}
}
return_code
cry_map_insert(struct CryMap* map, const_pointer key, pointer value)
......@@ -311,13 +402,107 @@ cry_map_insert(struct CryMap* map, const_pointer key, pointer value)
}
static void
rb_free_node(struct RBNode* node, cry_free_funptr key_free, cry_free_funptr val_free)
{
if(key_free != 0)
key_free(cry_cast(pointer, node->key));
if(val_free != 0)
val_free(node->value);
cry_free(node);
}
return_code
cry_map_remove(struct CryMap* map, const_pointer key, cry_free_funptr key_free, cry_free_funptr value_free)
struct RBNode*
rb_remove_external_node(struct RBNode* node, cry_free_funptr key_free)
{
return CRY_OKAY;
struct RBNode* child = (node->low == 0) ? node->high : node->low;
if(RB_PARENT(node)->low == node)
RB_PARENT(node)->low = child;
else
RB_PARENT(node)->high = child;
if(child != 0)
child->parent = RB_PARENT(node);
rb_free_node(node, key_free, 0);
return child;
}
pointer
cry_map_remove(struct CryMap* map, const_pointer key, cry_free_funptr key_free)
{
assert(map != 0 && key != 0);
struct RBNode* node = map->root;
struct RBNode* parent = 0;
struct RBNode* current_node = 0;
pointer data = 0;
// search for a node with the same key within the binary tree
while(current_node == 0) {
if(node == 0)
return data;
int result = map->compare(key, node->key);
if(result < 0) {
node = node->low;
} else if(result > 0) {
node = node->high;
} else {
current_node = node;
}
}
if(current_node->low != 0 && current_node->high != 0) {
// Find most-left internal node with an external child in the right subtree
node = current_node->high;
while(node->low != 0)
node = node->low;
// swap its entry information
const_pointer tmp_key = node->key;
pointer tmp_value = node->value;
node->key = current_node->key;
node->value = current_node->value;
current_node->key = tmp_key;
current_node->value = tmp_value;
data = node->value;
parent = RB_PARENT(node);
node = rb_remove_external_node(node, key_free);
} else {
// Remove internal node and replace it by its single subtree (Easy case)
data = current_node->value;
parent = RB_PARENT(current_node);
node = rb_remove_external_node(current_node, key_free);
}
// Node removed, now correct tree for red_black_tree properties
if(parent == 0) {
if(node != 0)
node->color = BLACK;
map->root = node;
} else if(node != 0 && (node->color == RED || parent->color == RED)) {
node->color = BLACK;
} else {
rb_remedy_double_black(map, parent, node);
}
map->nodes -= 1;
return data;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment