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

lib: implement Red-Black-Trees for maps using a generel ordering funptr.

lib: add double- and int comparator functions for maps.
parent ff39d2be
......@@ -2,16 +2,20 @@ set(SOURCES
unittest.c
structures/single_linked_list.c
structures/double_linked_list.c
structures/red_black_tree.c
structures/array.c
structures/structures.c
)
set(HEADER
standard.h
unix_colors.h
unittest.h
structures/structures.h
structures/array.h
structures/stack.h
structures/queue.h
structures/map.h
structures/list.h
)
......
/*
* 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/>.
*
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "map.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)
{
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))
printf("%s (%s)\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");
else if(compare == cry_double_compare)
printf("%lf (%s)\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);
rb_tree_dump_with_strings(map->root, map->compare, 0);
}
static struct RBNode*
create_rb_node(struct RBNode* parent, const_pointer key, pointer value, enum RBNodeColor color)
{
assert(key != 0);
struct RBNode* node = cry_malloc(struct RBNode);
node->parent = parent;
node->low = 0;
node->high = 0;
node->color = color;
node->key = key;
node->value = value;
return node;
}
void
cry_map_free(struct CryMap* map, cry_free_funptr key_free, cry_free_funptr value_free)
{
assert(map != 0);
// TODO: free all keys and values
cry_free(map);
}
size_t
cry_map_size(struct CryMap* map)
{
assert(map != 0);
return map->nodes;
}
pointer
cry_map_lookup(struct CryMap* map, const_pointer key)
{
assert(map != 0 && key != 0);
struct RBNode* node = map->root;
while(node != 0) {
int result = map->compare(key, node->key);
if(result < 0)
node = node->low;
else if(result > 0)
node = node->high;
else
return node->value;
}
return 0;
}
static struct RBNode*
rb_node_rotate_left(struct RBNode* node)
{
struct RBNode* parent = node->parent;
struct RBNode* high = node->high;
// switch right-node and its parent in a left-in-order rotation
node->high = high->low;
high->low = node;
// correct parent hierarchy
node->parent = high;
high->parent = parent;
if(parent != 0 && parent->low == node)
parent->low = high;
else if(parent != 0 && parent->high == node)
parent->high = high;
// return new sub_root
return high;
}
static struct RBNode*
rb_node_rotate_right(struct RBNode* node)
{
struct RBNode* parent = node->parent;
struct RBNode* low = node->low;
// 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(parent != 0 && parent->low == node)
parent->low = low;
else if(parent != 0 && parent->high == node)
parent->high = low;
// return new sub_root
return low;
}
static struct RBNode*
rb_trinode_restructering(struct RBNode* node)
{
struct RBNode* root = RB_GRAND_PARENT(node);
if(root->low == RB_PARENT(node)) {
if(RB_PARENT(node)->low == node)
root = rb_node_rotate_right(root);
else {
rb_node_rotate_left(RB_PARENT(node));
root = rb_node_rotate_right(root);
}
} else {
if(RB_PARENT(node)->high == node)
root = rb_node_rotate_left(root);
else {
rb_node_rotate_right(RB_PARENT(node));
root = rb_node_rotate_left(root);
}
}
return root;
}
static void
rb_remedy_double_red(struct CryMap* map, struct RBNode* node_z)
{
if(map->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) {
struct RBNode* node_v = rb_trinode_restructering(node_z);
node_v->color = BLACK;
node_v->low->color = RED;
node_v->high->color = RED;
while(node_v->parent != 0)
node_v = node_v->parent;
map->root = node_v;
} else {
RB_GRAND_PARENT(node_z)->low->color = BLACK;
RB_GRAND_PARENT(node_z)->high->color = BLACK;
if(map->root == RB_GRAND_PARENT(node_z))
return;
RB_GRAND_PARENT(node_z)->color = RED;
rb_remedy_double_red(map, RB_GRAND_PARENT(node_z));
}
}
return_code
cry_map_insert(struct CryMap* map, const_pointer key, pointer value)
{
assert(map != 0 && key != 0);
struct RBNode* node = map->root;
struct RBNode* current_node = 0;
if(node == 0) {
map->root = create_rb_node(node, key, value, BLACK);
map->nodes += 1;
return CRY_OKAY;
}
// general node insertion for binary search tree
while(current_node == 0) {
int result = map->compare(key, node->key);
if(result < 0) {
if(node->low == 0)
current_node = node->low = create_rb_node(node, key, value, RED);
else
node = node->low;
} else if(result > 0) {
if(node->high == 0)
current_node = node->high = create_rb_node(node, key, value, RED);
else
node = node->high;
} else {
return CRY_ENTRY_FULL;
}
}
// repair binary search tree based on red-black tree properties
rb_remedy_double_red(map, current_node);
map->nodes += 1;
return CRY_OKAY;
}
return_code
cry_map_remove(struct CryMap* map, const_pointer key, cry_free_funptr key_free, cry_free_funptr value_free)
{
return CRY_OKAY;
}
/*
* 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/>.
*
*/
#include "structures.h"
int
cry_int_compare(const_pointer a, const_pointer b)
{
if( *cry_cast(int*, a) < *cry_cast(int*, b))
return -1;
else if(*cry_cast(int*, a) > *cry_cast(int*, b))
return 1;
return 0;
}
int
cry_double_compare(const_pointer a, const_pointer b)
{
if(*cry_cast(double*, a) < *cry_cast(double*, b))
return -1;
else if(*cry_cast(double*, a) > *cry_cast(double*, b))
return 1;
return 0;
}
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