Commit e5973a9b authored by Chris Müller's avatar Chris Müller

lib: move red_black_tree implementation into its own module.

parent b1e27118
......@@ -19,219 +19,147 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "map.h"
#include "red_black_tree.h"
enum RBNodeColor { RED, BLACK };
struct RBNode {
const_pointer key;
pointer value;
enum RBNodeColor color;
struct RBNode* parent;
struct RBNode* low;
struct RBNode* high;
};
#define RB_PARENT(node) node->parent
#define RB_GRAND_PARENT(node) node->parent->parent
struct CryMap {
struct RBNode* root;
cry_ordering_funptr compare;
size_t nodes;
};
struct CryMap*
cry_map_new(cry_ordering_funptr compare)
struct RBTree*
rb_tree_new(cry_ordering_funptr compare)
{
assert(compare != 0);
struct CryMap* map = cry_malloc(struct CryMap);
map->root = 0;
map->compare = compare;
map->nodes = 0;
return map;
}
static void
rb_tree_dump_with_strings(struct RBNode* node, cry_ordering_funptr compare, size_t indent)
{
unsigned i = 0;
for(i = 0; i < indent; ++i)
printf(" ");
if(node == 0)
printf("null (BLACK)\n");
else {
if(compare == cry_cast(cry_ordering_funptr, strcmp))
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)
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)
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");
rb_tree_dump_with_strings(node->low, compare, indent + 4);
rb_tree_dump_with_strings(node->high, compare, indent + 4);
}
}
void
cry_map_dump_debug(struct CryMap* map)
{
assert(map != 0);
struct RBTree* tree = cry_malloc(struct RBTree);
tree->root = 0;
tree->compare = compare;
tree->nodes = 0;
rb_tree_dump_with_strings(map->root, map->compare, 0);
return tree;
}
static struct RBNode*
create_rb_node(struct RBNode* parent, const_pointer key, pointer value, enum RBNodeColor color)
struct RBNode*
rb_node_new(enum RBNodeColor color, struct RBNode* parent, const_pointer key, pointer data)
{
assert(key != 0);
struct RBNode* node = cry_malloc(struct RBNode);
node->parent = parent;
node->low = 0;
node->high = 0;
node->color = color;
node->parent = parent;
node->key = key;
node->value = value;
node->data = data;
node->left = 0;
node->right = 0;
return node;
}
void
cry_map_free(struct CryMap* map, cry_free_funptr key_free, cry_free_funptr value_free)
void
rb_tree_clear(struct RBTree* tree, cry_free_funptr free_key, cry_free_funptr free_data)
{
assert(map != 0);
assert(tree != 0);
// TODO: free all keys and values
cry_free(map);
}
// free elements
tree->root = 0;
tree->nodes = 0;
}
size_t
cry_map_size(struct CryMap* map)
void
rb_node_free(struct RBNode* node, cry_free_funptr free_key, cry_free_funptr free_data)
{
assert(map != 0);
assert(node != 0);
return map->nodes;
if(free_key != 0)
free_key(cry_cast(pointer, node->key));
if(free_data != 0)
free_data(node->data);
cry_free(node);
}
pointer
cry_map_lookup(struct CryMap* map, const_pointer key)
struct RBNode*
rb_tree_lookup(struct RBTree* tree, const_pointer key)
{
assert(map != 0 && key != 0);
assert(tree != 0 && key != 0);
struct RBNode* node = map->root;
struct RBNode* node = tree->root;
while(node != 0) {
int result = map->compare(key, node->key);
int result = tree->compare(key, node->key);
if(result < 0)
node = node->low;
if(result < 0)
node = node->left;
else if(result > 0)
node = node->high;
node = node->right;
else
return node->value;
return node;
}
return 0;
}
static struct RBNode*
rb_node_rotate_left(struct RBNode* node)
{
assert(node != 0);
struct RBNode* parent = node->parent;
struct RBNode* high = node->high;
struct RBNode* right = node->right;
// switch right-node and its parent in a left-in-order rotation
node->high = high->low;
high->low = node;
node->right = right->left;
right->left = node;
// correct parent hierarchy
node->parent = high;
high->parent = parent;
node->parent = right;
right->parent = parent;
if(node->high != 0)
node->high->parent = node;
//node->high->parent = node;
if(node->right != 0)
node->right->parent = node;
if(parent != 0 && parent->low == node)
parent->low = high;
else if(parent != 0 && parent->high == node)
parent->high = high;
if(parent != 0 && parent->left == node)
parent->left = right;
else if(parent != 0 && parent->right == node)
parent->right = right;
// return new sub_root
return high;
return right;
}
static struct RBNode*
rb_node_rotate_right(struct RBNode* node)
{
assert(node != 0);
struct RBNode* parent = node->parent;
struct RBNode* low = node->low;
struct RBNode* left = node->left;
// switch left-node and its parent in a right-in-order rotation
node->low = low->high;
low->high = node;
node->left = left->right;
left->right = node;
// correct parent hierarchy
node->parent = low;
low->parent = parent;
node->parent = left;
left->parent = parent;
if(node->low != 0)
node->low->parent = node;
//node->low->parent = node;
if(node->left != 0)
node->left->parent = node;
if(parent != 0 && parent->low == node)
parent->low = low;
else if(parent != 0 && parent->high == node)
parent->high = low;
if(parent != 0 && parent->left == node)
parent->left = left;
else if(parent != 0 && parent->right == node)
parent->right = left;
// return new sub_root
return low;
return left;
}
......@@ -239,9 +167,11 @@ rb_node_rotate_right(struct RBNode* node)
static struct RBNode*
rb_trinode_restructering(struct RBNode* node)
{
assert(node != 0);
struct RBNode* root = RB_GRAND_PARENT(node);
if(root->low == RB_PARENT(node)) {
if(RB_PARENT(node)->low == node)
if(root->left == RB_PARENT(node)) {
if(RB_PARENT(node)->left == node)
root = rb_node_rotate_right(root);
else {
rb_node_rotate_left(RB_PARENT(node));
......@@ -249,7 +179,7 @@ rb_trinode_restructering(struct RBNode* node)
}
} else {
if(RB_PARENT(node)->high == node)
if(RB_PARENT(node)->right == node)
root = rb_node_rotate_left(root);
else {
rb_node_rotate_right(RB_PARENT(node));
......@@ -262,43 +192,47 @@ rb_trinode_restructering(struct RBNode* node)
static void
rb_remedy_double_red(struct CryMap* map, struct RBNode* node_z)
rb_remedy_double_red(struct RBTree* tree, struct RBNode* node_z)
{
if(map->root == RB_PARENT(node_z))
assert(tree != 0 && node_z != 0);
if(tree->root == RB_PARENT(node_z))
return;
else if(RB_PARENT(node_z)->color == BLACK)
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) {
if(RB_GRAND_PARENT(node_z)->left == 0 || RB_GRAND_PARENT(node_z)->right == 0 || RB_GRAND_PARENT(node_z)->left->color == BLACK || RB_GRAND_PARENT(node_z)->right->color == BLACK) {
// trinode restructering with single/multiple left- and right rotations
struct RBNode* node_v = rb_trinode_restructering(node_z);
node_v->color = BLACK;
node_v->low->color = RED;
node_v->high->color = RED;
node_v->left->color = RED;
node_v->right->color = RED;
while(node_v->parent != 0)
node_v = node_v->parent;
map->root = node_v;
tree->root = node_v;
} else {
// recoloring of nodes
RB_GRAND_PARENT(node_z)->low->color = BLACK;
RB_GRAND_PARENT(node_z)->high->color = BLACK;
RB_GRAND_PARENT(node_z)->left->color = BLACK;
RB_GRAND_PARENT(node_z)->right->color = BLACK;
if(RB_GRAND_PARENT(node_z)->parent == 0)
return;
RB_GRAND_PARENT(node_z)->color = RED;
rb_remedy_double_red(map, RB_GRAND_PARENT(node_z));
rb_remedy_double_red(tree, RB_GRAND_PARENT(node_z));
}
}
static void
rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode* node_r)
rb_remedy_double_black(struct RBTree* tree, struct RBNode* node_x, struct RBNode* node_r)
{
struct RBNode* sibling = (node_x->low == node_r) ? node_x->high : node_x->low;
assert(node_x != 0);
struct RBNode* sibling = (node_x->left == node_r) ? node_x->right : node_x->left;
struct RBNode* child = 0;
if(sibling == 0)
......@@ -308,10 +242,10 @@ rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode*
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(sibling->left != 0 && sibling->left->color == RED)
child = sibling->left;
else if(sibling->right != 0 && sibling->right->color == RED)
child = sibling->right;
if(child != 0) {
// Case 1: Restructering of siblings red child
......@@ -320,12 +254,12 @@ rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode*
child->color = parent_color;
if(node_r != 0)
node_r->color = BLACK;
child->low->color = BLACK;
child->high->color = BLACK;
child->left->color = BLACK;
child->right->color = BLACK;
while(child->parent != 0)
child = child->parent;
map->root = child;
tree->root = child;
} else {
// Case 2: Both siblings childs are black => Recoloring
if(node_r != 0)
......@@ -334,16 +268,16 @@ rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode*
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);
rb_remedy_double_black(tree, RB_PARENT(node_x), node_x);
}
}
} else {
// Case 3: Sibling is red => Adjustment needed
if(node_x->high == sibling)
child = sibling->high;
if(node_x->right == sibling)
child = sibling->right;
else
child = sibling->low;
child = sibling->left;
if(child != 0) {
child = rb_trinode_restructering(child);
......@@ -352,156 +286,128 @@ rb_remedy_double_black(struct CryMap* map, struct RBNode* node_x, struct RBNode*
while(child->parent != 0)
child = child->parent;
map->root = child;
tree->root = child;
rb_remedy_double_black(map, node_x, node_r);
rb_remedy_double_black(tree, node_x, node_r);
}
}
}
return_code
cry_map_insert(struct CryMap* map, const_pointer key, pointer value)
struct RBNode*
rb_tree_insert(struct RBTree* tree, const_pointer key, pointer value)
{
assert(map != 0 && key != 0);
assert(tree != 0 && key != 0);
struct RBNode* node = map->root;
struct RBNode* node = tree->root;
struct RBNode* current_node = 0;
if(node == 0) {
map->root = create_rb_node(node, key, value, BLACK);
map->nodes += 1;
return CRY_OKAY;
tree->root = rb_node_new(BLACK, 0, key, value);
tree->nodes += 1;
return tree->root;
}
// general node insertion for binary search tree
while(current_node == 0) {
int result = map->compare(key, node->key);
int result = tree->compare(key, node->key);
if(result < 0) {
if(node->low == 0)
current_node = node->low = create_rb_node(node, key, value, RED);
if(node->left == 0)
current_node = node->left = rb_node_new(RED, node, key, value);
else
node = node->low;
node = node->left;
} else if(result > 0) {
if(node->high == 0)
current_node = node->high = create_rb_node(node, key, value, RED);
if(node->right == 0)
current_node = node->right = rb_node_new(RED, node, key, value);
else
node = node->high;
node = node->right;
} else {
return CRY_ENTRY_FULL;
return 0;
}
}
// repair binary search tree based on red-black tree properties
rb_remedy_double_red(map, current_node);
rb_remedy_double_red(tree, current_node);
map->nodes += 1;
tree->nodes += 1;
return CRY_OKAY;
return current_node;
}
static void
rb_free_node(struct RBNode* node, cry_free_funptr key_free, cry_free_funptr val_free)
static struct RBNode*
rb_remove_external_node(struct RBNode* node)
{
if(key_free != 0)
key_free(cry_cast(pointer, node->key));
assert(node != 0);
if(val_free != 0)
val_free(node->value);
struct RBNode* child = (node->left == 0) ? node->right : node->left;
cry_free(node);
}
struct RBNode*
rb_remove_external_node(struct RBNode* node, cry_free_funptr key_free)
{
struct RBNode* child = (node->low == 0) ? node->high : node->low;
if(RB_PARENT(node)->low == node)
RB_PARENT(node)->low = child;
if(RB_PARENT(node)->left == node)
RB_PARENT(node)->left = child;
else
RB_PARENT(node)->high = child;
RB_PARENT(node)->right = 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)
struct RBNode*
rb_tree_remove(struct RBTree* tree, const_pointer key)
{
assert(map != 0 && key != 0);
assert(tree != 0 && key != 0);
struct RBNode* node = map->root;
struct RBNode* parent = 0;
struct RBNode* node = tree->root;
struct RBNode* current_node = 0;
pointer data = 0;
struct RBNode* data_node = 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;
}
}
current_node = rb_tree_lookup(tree, key);
if(current_node->low != 0 && current_node->high != 0) {
if(current_node == 0)
return current_node;
else if(current_node->left != 0 && current_node->right != 0) {
// Find most-left internal node with an external child in the right subtree
node = current_node->high;
node = current_node->right;
while(node->low != 0)
node = node->low;
while(node->left != 0)
node = node->left;
// swap its entry information
const_pointer tmp_key = node->key;
pointer tmp_value = node->value;
pointer tmp_data = node->data;
node->key = current_node->key;
node->value = current_node->value;
node->data = current_node->data;
current_node->key = tmp_key;
current_node->value = tmp_value;
current_node->data = tmp_data;
data = node->value;
parent = RB_PARENT(node);
node = rb_remove_external_node(node, key_free);
data_node = node;
node = rb_remove_external_node(node);
} 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);
data_node = current_node;
node = rb_remove_external_node(current_node);
}
// Node removed, now correct tree for red_black_tree properties
if(parent == 0) {
if(RB_PARENT(data_node) == 0) {
if(node != 0)
node->color = BLACK;
map->root = node;
} else if(node != 0 && (node->color == RED || parent->color == RED)) {
tree->root = node;
} else if(node != 0 && (node->color == RED || RB_PARENT(data_node)->color == RED)) {
node->color = BLACK;
} else {
rb_remedy_double_black(map, parent, node);
rb_remedy_double_black(tree, RB_PARENT(data_node), node);
}
map->nodes -= 1;
tree->nodes -= 1;
return data;
return data_node;
}
......
/*
* Copyright (c) 2012 Christoph Mueller <ruunhb@googlemail.com>
*
* Crystal is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Crystal is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CRYSTAL_STRUCTURES_REDBLACKTREE_H
#define CRYSTAL_STRUCTURES_REDBLACKTREE_H
#include "structures.h"
enum RBNodeColor { RED, BLACK };
struct RBNode {
const_pointer key;
pointer data;
enum RBNodeColor color;
struct RBNode* parent;
struct RBNode* left;
struct RBNode* right;