So, below is my crack at it... maybe someday I'll get around to annotating it so this will be meaningful, for now you are on your own.
static int
__tree_node_is_red(tree_node_t *n)
{
return n && n->color == RED;
}
static int
__tree_node_is_black(tree_node_t *n)
{
return n && n->color == BLACK;
}
static tree_node_t *
__tree_node_rotate(tree_node_t *n, tree_node_link_t dir)
{
tree_node_t *p;
assert(dir == LEFT || dir == RIGHT);
p = n->link[!dir];
/* child of p -> child of n */
n->link[!dir] = p->link[dir];
if (n->link[!dir])
n->link[!dir]->link[PARENT] = n;
/* parent of n -> parent of p */
p->link[PARENT] = n->link[PARENT];
if (p->link[PARENT]) {
if (n == p->link[PARENT]->link[dir]) {
p->link[PARENT]->link[dir] = p;
} else {
p->link[PARENT]->link[!dir] = p;
}
}
/* swap p and n */
p->link[dir] = n;
n->link[PARENT] = p;
return p;
}
static tree_node_t *
__tree_node_split(tree_node_t *n)
{
tree_node_t *p = __tree_node_rotate(n, RIGHT);
p->link[LEFT]->color = BLACK;
return p;
}
static tree_node_t *
__tree_node_lean(tree_node_t *n, tree_node_link_t dir)
{
tree_node_t *p = __tree_node_rotate(n, dir);
p->color = p->link[dir]->color;
p->link[dir]->color = RED;
return p;
}
void *
tree_insert(tree_t *t, void *key, void *val)
{
int c;
tree_node_t *n, *p;
void *r = NULL;
assert(t);
for (p = NULL, n = t->root; n; p = n, n = n->link[c > 0]) {
#ifdef BALANCE
/* split four nodes on the way down the path */
if (__tree_node_is_red(n->link[LEFT]))
if (__tree_node_is_red(n->link[LEFT]->link[LEFT]))
n = __tree_node_split(n);
#endif
/* replace an existing entry */
if ((c = t->cmp(key, n->entry[KEY])) == 0) {
r = n->entry[VALUE];
n->entry[VALUE] = val;
break;
}
}
/* adding a new node */
try {
if (!r) {
n = __tree_node_create(t, p, key, val);
throw_unless(n) out_of_memory;
if (p) {
p->link[c > 0] = n;
}
}
#ifdef BALANCE
/* lean red links left on the way up the path */
for ( ; p; n = p, p = p->link[PARENT])
if (__tree_node_is_red(p->link[RIGHT]))
p = __tree_node_lean(p, LEFT);
#endif
/* created (or rotated) a new root if parent is null */
if (!n->link[PARENT]) {
t->root = n;
n->color = BLACK;
}
t->size++;
} catch (out_of_memory) { }
return NULL;
}
static tree_node_t *
__tree_node_move(tree_node_t *n, tree_node_link_t dir)
{
n->color = BLACK;
n->link[dir]->color = RED;
if (__tree_node_is_red(n->link[!dir]->link[LEFT])) {
if (dir) {
n = __tree_node_rotate(n, dir);
n->color = RED;
n->link[!dir]->color = BLACK;
} else {
n->link[!dir] = __tree_node_rotate(n->link[!dir], !dir);
n = __tree_node_rotate(n, dir);
}
} else {
n->link[!dir]->color = RED;
}
return n;
}
void *
tree_remove(tree_t *t, void *key)
{
int c = 1;
tree_node_t *n, *p;
void *r = NULL;
assert(t);
for (p = NULL, n = t->root; n && c; p = n, n = n->link[c > 0]) {
c = t->cmp(key, n->entry[KEY]);
if (c < 0) {
/* push red right */
if (__tree_node_is_black(n->link[LEFT]) &&
__tree_node_is_black(n->link[LEFT]->link[LEFT]))
n = __tree_node_move(n, LEFT);
} else if (c > 0) {
if (__tree_node_is_red(n->link[LEFT]))
n = __tree_node_lean(n, RIGHT);
if (__tree_node_is_black(n->link[RIGHT]) &&
__tree_node_is_black(n->link[RIGHT]->link[LEFT]))
n = __tree_node_move(n, RIGHT);
} else {
if (n->link[RIGHT]) {
tree_node_t *m = n->link[RIGHT];
/* find successor */
while (m->link[LEFT])
m = m->link[LEFT];
/* replace and continue search */
n->entry[KEY] = m->entry[KEY];
n->entry[VALUE] = m->entry[VALUE];
key = m->entry[KEY];
c = 1; /* force move right */
} else if (n->link[PARENT]) {
/* delete leaf, replace parent's pointer to this
* node with pointer to this node's left child */
p->link[p->link[LEFT] != n] = n->link[LEFT];
if (n->link[LEFT])
n->link[LEFT]->link[PARENT] = p;
} else {
/* delete root */
t->root = n->link[LEFT];
if (n->link[LEFT])
n->link[LEFT]->link[PARENT] = NULL;
}
}
}
for (n = p; n->link[PARENT]; n = n->link[PARENT])
if (__tree_node_is_red(n->link[RIGHT]))
n = __tree_node_lean(n, LEFT);
__tree_node_delete(t, p);
return r;
}
No comments:
Post a Comment