working single-level red/black tree code

This commit is contained in:
David Lawrence
1999-01-20 10:18:34 +00:00
parent f389bc2c9e
commit 910b2a8092
2 changed files with 359 additions and 64 deletions

View File

@@ -22,8 +22,16 @@
#include <isc/result.h>
typedef struct RBT_NODE *RBT_NODE_T;
typedef struct _isc_rbt_node {
enum { red, black } color;
void *data;
struct _isc_rbt_node *parent;
struct _isc_rbt_node *right;
struct _isc_rbt_node *left;
} RBT_NODE;
RBT_LINKAGE isc_result_t RBT_INSERT(RBT_NODE_T, RBT_NODE_T *);
RBT_LINKAGE RBT_NODE_T RBT_SEARCH(RBT_NODE_T, RBT_KEY_T);
RBT_LINKAGE void RBT_PRINT(RBT_NODE_T);
isc_result_t RBT_INSERT(RBT_NODE *, RBT_NODE **,
int (*compare)(void *, void*));
isc_result_t RBT_DELETE(RBT_NODE *, RBT_NODE **);
RBT_NODE *RBT_SEARCH(RBT_NODE *, void *, int (*compare)(void *, void*));
void RBT_PRINT(RBT_NODE *, void (*print_key)(void *));

View File

@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <stddef.h>
#include <isc/rbtgen.h>
#include <isc/boolean.h>
#include <isc/assertions.h>
@@ -49,9 +50,26 @@
#define TRACE_NODE(n)
#endif
#define COLOR(node) ((node)->color)
#define KEY(node) ((node)->data)
#define LEFT(node) ((node)->left)
#define RIGHT(node) ((node)->right)
#define PARENT(node) ((node)->parent)
#define SET_COLOR(node, value) ((node)->color = (value))
#define SET_KEY(node, value) ((node)->data = (value))
#define SET_LEFT(node, child) ((node)->left = (child))
#define SET_RIGHT(node, child) ((node)->right = (child))
#define SET_PARENT(node, child) ((node)->parent = (child))
#define IS_RED(node) ((node) != NULL && (node)->color == red)
#define IS_BLACK(node) ((node) == NULL || (node)->color == black)
#define MAKE_RED(node) ((node)->color = red)
#define MAKE_BLACK(node) ((node)->color = black)
static inline void
rotate_left(RBT_NODE_T node, RBT_NODE_T parent, RBT_NODE_T *rootp) {
RBT_NODE_T child;
rotate_left(RBT_NODE *node, RBT_NODE **rootp) {
RBT_NODE *child;
REQUIRE(node != NULL);
REQUIRE(rootp != NULL);
@@ -60,21 +78,26 @@ rotate_left(RBT_NODE_T node, RBT_NODE_T parent, RBT_NODE_T *rootp) {
REQUIRE(child != NULL);
SET_RIGHT(node, LEFT(child));
if (LEFT(child) != NULL)
SET_PARENT(LEFT(child), node);
SET_LEFT(child, node);
if (parent != NULL) {
if (LEFT(parent) == node)
SET_LEFT(parent, child);
SET_PARENT(child, PARENT(node));
if (PARENT(node) != NULL) {
if (LEFT(PARENT(node)) == node)
SET_LEFT(PARENT(node), child);
else {
INSIST(RIGHT(parent) == node); /* XXX remove */
SET_RIGHT(parent, child);
SET_RIGHT(PARENT(node), child);
}
} else
*rootp = child;
SET_PARENT(node, child);
}
static inline void
rotate_right(RBT_NODE_T node, RBT_NODE_T parent, RBT_NODE_T *rootp) {
RBT_NODE_T child;
rotate_right(RBT_NODE *node, RBT_NODE **rootp) {
RBT_NODE *child;
REQUIRE(node != NULL);
REQUIRE(rootp != NULL);
@@ -83,27 +106,30 @@ rotate_right(RBT_NODE_T node, RBT_NODE_T parent, RBT_NODE_T *rootp) {
REQUIRE(child != NULL);
SET_LEFT(node, RIGHT(child));
if (RIGHT(child) != NULL)
SET_PARENT(RIGHT(child), node);
SET_RIGHT(child, node);
if (parent != NULL) {
if (LEFT(parent) == node)
SET_LEFT(parent, child);
else {
INSIST(RIGHT(parent) == node); /* XXX remove */
SET_RIGHT(parent, child);
}
SET_PARENT(child, PARENT(node));
if (PARENT(node) != NULL) {
if (LEFT(PARENT(node)) == node)
SET_LEFT(PARENT(node), child);
else
SET_RIGHT(PARENT(node), child);
} else
*rootp = child;
SET_PARENT(node, child);
}
isc_result_t
RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
RBT_NODE_T current, child, root, parent, grandparent, tmp;
RBT_INSERT(RBT_NODE *node, RBT_NODE **rootp, int (*compare)(void *, void *)) {
RBT_NODE *current, *child, *root, *parent, *grandparent;
int i;
unsigned int depth = 0;
RBT_NODE_T ancestors[MAX_DEPTH];
REQUIRE(rootp != NULL);
REQUIRE(LEFT(node) == NULL && RIGHT(node) == NULL);
REQUIRE(KEY(node) != NULL);
root = *rootp;
if (root == NULL) {
@@ -115,11 +141,8 @@ RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
current = NULL;
child = root;
do {
INSIST(depth < MAX_DEPTH);
ancestors[depth] = current;
depth++;
current = child;
i = COMPARE_KEYS(KEY(node), KEY(current));
i = compare(KEY(node), KEY(current));
if (i == 0)
return (ISC_R_EXISTS);
if (i < 0)
@@ -127,17 +150,16 @@ RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
else
child = RIGHT(current);
} while (child != NULL);
INSIST(depth < MAX_DEPTH);
ancestors[depth] = current;
if (i < 0)
SET_LEFT(current, node);
else
SET_RIGHT(current, node);
MAKE_RED(node);
SET_PARENT(node, current);
while (node != root && IS_RED(ancestors[depth])) {
parent = ancestors[depth];
grandparent = ancestors[depth - 1];
while (node != root && IS_RED(PARENT(node))) {
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
TRACE_NODE(n);
@@ -149,24 +171,18 @@ RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
depth -= 2;
} else {
if (node == RIGHT(parent)) {
TRACE_CASE(2);
tmp = node;
rotate_left(parent, grandparent,
&root);
node = parent;
parent = tmp;
ancestors[depth] = parent;
/* Note: depth does not change. */
rotate_left(node, &root);
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
}
TRACE_CASE(3);
MAKE_BLACK(parent);
MAKE_RED(grandparent);
INSIST(depth >= 2); /* XXX */
tmp = ancestors[depth - 2];
rotate_right(grandparent, tmp, &root);
rotate_right(grandparent, &root);
}
} else {
child = LEFT(grandparent);
@@ -176,24 +192,18 @@ RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
depth -= 2;
} else {
if (node == LEFT(parent)) {
TRACE_CASE(5);
tmp = node;
rotate_right(parent, grandparent,
&root);
node = parent;
parent = tmp;
ancestors[depth] = parent;
/* Note: depth does not change. */
rotate_right(node, &root);
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
}
TRACE_CASE(6);
MAKE_BLACK(parent);
MAKE_RED(grandparent);
INSIST(depth >= 2); /* XXX */
tmp = ancestors[depth - 2];
rotate_left(grandparent, tmp, &root);
rotate_left(grandparent, &root);
}
}
}
@@ -204,12 +214,192 @@ RBT_INSERT(RBT_NODE_T node, RBT_NODE_T *rootp) {
return (ISC_R_SUCCESS);
}
RBT_NODE_T
RBT_SEARCH(RBT_NODE_T current, RBT_KEY_T key) {
/* node must belong to a pointer in the tree; how could this be ensured? */
isc_result_t
RBT_DELETE(RBT_NODE *delete, RBT_NODE **rootp) {
RBT_NODE *successor, *sibling, *child = NULL;
REQUIRE(rootp != NULL);
REQUIRE(delete);
if (LEFT(delete) == NULL)
if (RIGHT(delete) == NULL) {
if (*rootp == delete) {
/* this is the only item in the tree */
*rootp = NULL;
return(ISC_R_SUCCESS);
}
} else
/* this node has one child, on the right */
child = RIGHT(delete);
else if (RIGHT(delete) == NULL)
/* this node has one child, on the left */
child = LEFT(delete);
else {
RBT_NODE holder, *tmp = &holder;
/* this node has two children, so it cannot be directly
deleted. find its immediate in-order successor and
move it to this location, then do the deletion at the
old site of the successor */
successor = RIGHT(delete);
while (LEFT(successor) != NULL)
successor = LEFT(successor);
/* the successor cannot possibly have a left child;
if there is any child, it is on the right */
if (RIGHT(successor))
child = RIGHT(successor);
/* swap the two nodes; it would be simpler to just replace
the value being deleted with that of the successor,
but this rigamarole is done so the caller has complete
control over the pointers (and memory allocation) of
all of nodes. if just the key value were removed from
the tree, the pointer to the node would would be
unchanged. */
/* first, put the successor in the tree location of the
node to be deleted */
memcpy(tmp, successor, sizeof(RBT_NODE));
if (LEFT(PARENT(delete)) == delete)
SET_LEFT(PARENT(delete), successor);
else
SET_RIGHT(PARENT(delete), successor);
SET_PARENT(successor, PARENT(delete));
if (LEFT(delete) != NULL)
SET_PARENT(LEFT(delete), successor);
if (RIGHT(delete) != NULL && RIGHT(delete) != successor)
SET_PARENT(RIGHT(delete), successor);
SET_COLOR(successor, COLOR(delete));
SET_LEFT(successor, LEFT(delete));
SET_RIGHT(successor, RIGHT(delete));
/* now relink the node to be deleted into the
successor's previous tree location */
if (PARENT(tmp) != delete) {
if (LEFT(PARENT(tmp)) == successor)
SET_LEFT(PARENT(tmp), delete);
else
SET_RIGHT(PARENT(tmp), delete);
SET_PARENT(delete, PARENT(tmp));
} else
SET_PARENT(delete, successor);
/* original successor node has no left */
if (RIGHT(tmp) != NULL)
SET_PARENT(RIGHT(tmp), delete);
SET_COLOR(delete, COLOR(tmp));
SET_LEFT(delete, LEFT(tmp));
SET_RIGHT(delete, RIGHT(tmp));
}
/* fix the parent chain if a non-leaf is being deleted */
if (PARENT(delete) != NULL) {
if (LEFT(PARENT(delete)) == delete) {
SET_LEFT(PARENT(delete), child);
sibling = RIGHT(PARENT(delete));
} else {
SET_RIGHT(PARENT(delete), child);
sibling = LEFT(PARENT(delete));
}
if (child != NULL)
SET_PARENT(child, PARENT(delete));
} else {
/* this is the root being deleted, with just one child */
SET_PARENT(child, NULL);
sibling= NULL;
*rootp = child;
}
/* fix color violations */
if (IS_BLACK(delete)) {
RBT_NODE *parent;
parent = PARENT(delete);
while (child != *rootp && IS_BLACK(child)) {
/* parent = PARENT(parent_pointer); */
if (LEFT(parent) == child) {
sibling = RIGHT(parent);
if (IS_RED(sibling)) {
MAKE_BLACK(sibling);
MAKE_RED(parent);
rotate_left(parent, rootp);
sibling = RIGHT(parent);
}
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
child = parent;
} else {
if (IS_BLACK(RIGHT(sibling))) {
MAKE_BLACK(LEFT(sibling));
MAKE_RED(sibling);
rotate_right(sibling, rootp);
sibling = RIGHT(parent);
}
SET_COLOR(sibling, COLOR(parent));
MAKE_BLACK(parent);
MAKE_BLACK(RIGHT(sibling));
rotate_left(parent, rootp);
child = *rootp;
}
} else {
sibling = LEFT(parent);
if (IS_RED(sibling)) {
MAKE_BLACK(sibling);
MAKE_RED(parent);
rotate_right(parent, rootp);
sibling = LEFT(parent);
}
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
child = parent;
} else {
if (IS_BLACK(LEFT(sibling))) {
MAKE_BLACK(RIGHT(sibling));
MAKE_RED(sibling);
rotate_left(sibling, rootp);
sibling = LEFT(parent);
}
SET_COLOR(sibling, COLOR(parent));
MAKE_BLACK(parent);
MAKE_BLACK(LEFT(sibling));
rotate_right(parent, rootp);
child = *rootp;
}
}
parent = PARENT(child);
}
if (IS_RED(child))
MAKE_BLACK(child);
}
return(ISC_R_SUCCESS);
}
RBT_NODE *
RBT_SEARCH(RBT_NODE *current, void *key, int (*compare)(void *, void *)) {
int i;
while (current != NULL) {
i = COMPARE_KEYS(key, KEY(current));
i = compare(key, KEY(current));
if (i == 0)
break;
if (i < 0)
@@ -218,26 +408,123 @@ RBT_SEARCH(RBT_NODE_T current, RBT_KEY_T key) {
current = RIGHT(current);
}
return (current);
return(current);
}
static inline void
print_tree(RBT_NODE_T root, int depth) {
print_tree(RBT_NODE *root, void (*print_key)(void *), int depth) {
int i;
for (i = 0; i < depth; i++)
putchar('\t');
if (root != NULL) {
PRINT_KEY(KEY(root));
printf(" (%s)\n", IS_RED(root) ? "red" : "black");
print_key(KEY(root));
printf(" (%s", IS_RED(root) ? "RED" : "black");
if (root->parent) {
printf(" from ");
print_key(KEY(root->parent));
}
printf(")\n");
depth++;
print_tree(LEFT(root), depth);
print_tree(RIGHT(root), depth);
if (IS_RED(root) && IS_RED(LEFT(root)))
printf("** Red/Red color violation on left\n");
print_tree(LEFT(root), print_key, depth);
if (IS_RED(root) && IS_RED(RIGHT(root)))
printf("** Red/Red color violation on right\n");
print_tree(RIGHT(root), print_key, depth);
} else
printf("NULL\n");
}
void
RBT_PRINT(RBT_NODE_T root) {
print_tree(root, 0);
RBT_PRINT(RBT_NODE *root, void (*print_key)(void *)) {
print_tree(root, print_key, 0);
}
#ifdef WANT_RBTGEN_MAIN
int compare_int(void *, void *);
void print_int(void *);
int ints[] = { 12679, 26804, 7389, 20562, 24355, 23584,
10713, 8094, 19071, 6732, 2709, 6058,
3995, 3896, 15121, 1142, 2679, 26340,
30541, 29186,
#if 0
6584, 13201, 21238, 30455, 6500, 30669,
10370, 2963, 26576, 17353, 19150, 19951,
12540, 21381, 17882, 23051, 24808, 8961,
26022, 3047, 9108, 28221, 13874, 32643,
25856, 12601, 894, 4319, 20780, 10229,
#endif
0 };
int
compare_int(void *a, void *b) {
int i = *(int *)a, j = *(int *)b;
return(i == j ? 0 : (i < j ? -1 : 1));
}
void
print_int(void *num) {
int i = *(int *)num;
(void)printf("%d", i);
}
#define KEY_VALUE(node, type) (*(type *)((node)->data))
void
main() {
RBT_NODE nodes[sizeof(ints)/sizeof(int)], *p, *root;
int *i, j;
setbuf(stdout, NULL);
printf("For any two successive numbers at the same depth, the\n");
printf("first number (and all its descendants) should be less than\n");
printf("the number which immediately precedes it one depth level\n");
printf("higher, and the second number (and all its descendants)\n");
printf("should be greater than that preceding number\n\n");
for (i = &ints[0], p = &nodes[0]; *i != 0; i++, p++) {
printf("inserting %d\n", *i);
KEY(p) = i;
RBT_INSERT(p, &root, compare_int);
RBT_PRINT(root, print_int);
}
j = 2679;
i = &j;
printf("searching for %d ...", j);
p = RBT_SEARCH(root, i, compare_int);
if (p != NULL) {
printf("found %d\n", KEY_VALUE(p, int));
} else {
printf("not found!\n");
}
j = 9999;
i = &j;
printf("searching for %d ...", j);
p = RBT_SEARCH(root, i, compare_int);
if (p != NULL) {
printf("found %d\n", KEY_VALUE(p, int));
} else {
printf("not found!\n");
}
p = &nodes[sizeof(ints) / sizeof(int) - 2];
do {
printf("deleting %d\n", KEY_VALUE(p, int));
RBT_DELETE(p, &root);
RBT_PRINT(root, print_int);
} while (p-- != &nodes[0]);
exit(0);
}
#endif