337 lines
7.2 KiB
C
337 lines
7.2 KiB
C
/* This software is licensed by the MIT License, see LICENSE file */
|
|
/* Copyright © 2022 Gregory Lirent */
|
|
|
|
#include "__internal/rbtree.h"
|
|
|
|
typedef enum libcdsb_rbtree_node_direction {
|
|
RBD_LEFT = 1,
|
|
RBD_RIGHT = 2
|
|
} rbdir_t;
|
|
|
|
#define rbdir_dir(cur, d) (&((cur)->left))[(d)>>1]
|
|
#define rbdir_inv(cur, d) (&((cur)->left))[(d)&1]
|
|
|
|
#define rotate libcdsb_builtin_rotate
|
|
#define replace libcdsb_builtin_replace
|
|
#define fixup libcdsb_builtin_fixup
|
|
|
|
|
|
static void libcdsb_builtin_rotate(rbnode_t **x, rbnode_t *c, rbdir_t d) {
|
|
rbnode_t* n = rbdir_inv(c, d);
|
|
|
|
rbdir_inv(c, d) = rbdir_dir(n, d);
|
|
n->parent = c->parent;
|
|
|
|
if (!rbnode_is_empty(rbdir_dir(n, d)))
|
|
rbdir_dir(n, d)->parent = c;
|
|
|
|
if (!rbnode_is_root(c)) {
|
|
if (c->parent->left == c) c->parent->left = n;
|
|
else c->parent->right = n;
|
|
} else *x = n;
|
|
|
|
rbdir_dir(n, d) = c;
|
|
c->parent = n;
|
|
}
|
|
|
|
|
|
static void libcdsb_builtin_replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) {
|
|
if (!rbnode_is_root(c)) {
|
|
if (c->parent->left == c) {
|
|
c->parent->left = n;
|
|
} else c->parent->right = n;
|
|
} else *x = n;
|
|
n->parent = c->parent;
|
|
}
|
|
|
|
|
|
static void libcdsb_builtin_fixup(rbnode_t** x, rbnode_t* n) {
|
|
rbdir_t d;
|
|
rbnode_t *s, *p;
|
|
|
|
while (!rbnode_is_root(n) && !n->colored) {
|
|
p = n->parent;
|
|
d = (p->left == n) ? RBD_LEFT : RBD_RIGHT;
|
|
s = rbdir_inv(p, d);
|
|
|
|
if (s->colored) {
|
|
s->colored = 0;
|
|
p->colored = 1;
|
|
rotate(x, p, d);
|
|
p = n->parent;
|
|
s = rbdir_inv(p, d);
|
|
}
|
|
|
|
if (!rbdir_dir(s, d)->colored && !rbdir_inv(s, d)->colored) {
|
|
s->colored = 1;
|
|
n = p;
|
|
} else {
|
|
if (!rbdir_inv(s, d)->colored) {
|
|
rbdir_dir(s, d)->colored = 0;
|
|
s->colored = 1;
|
|
rotate(x, s, (d == RBD_LEFT) ? RBD_RIGHT : RBD_LEFT);
|
|
p = n->parent;
|
|
s = rbdir_inv(p, d);
|
|
}
|
|
|
|
s->colored = p->colored;
|
|
p->colored = 0;
|
|
rbdir_inv(s, d)->colored = 0;
|
|
|
|
rotate(x, p, d);
|
|
|
|
n = *x;
|
|
}
|
|
}
|
|
|
|
n->colored = 0;
|
|
}
|
|
|
|
/*#####################################################################################################################*/
|
|
|
|
rbnode_t LIBCDSB_BUILTIN_RBTREE_NODE_EMPTY[1] = {{
|
|
.colored = 0,
|
|
.value = 0,
|
|
.parent = rbnode_empty,
|
|
.left = rbnode_empty,
|
|
.right = rbnode_empty
|
|
}};
|
|
|
|
|
|
rbnode_t* libcdsb_builtin_rbtree_node_delete(rbnode_t** x, rbnode_t* c) {
|
|
rbnode_t *n, *t;
|
|
int s;
|
|
|
|
s = c->colored;
|
|
|
|
if (rbnode_is_empty(c->left)) {
|
|
n = c->right;
|
|
replace(x, c, c->right);
|
|
} else if (rbnode_is_empty(c->right)) {
|
|
n = c->left;
|
|
replace(x, c, c->left);
|
|
} else {
|
|
t = c->right;
|
|
|
|
while (!rbnode_is_empty(t->left)) {
|
|
t = t->left;
|
|
}
|
|
|
|
s = t->colored;
|
|
n = t->right;
|
|
|
|
if (t->parent == c) {
|
|
n->parent = t;
|
|
} else {
|
|
replace(x, t, t->right);
|
|
c->right->parent = t;
|
|
t->right = c->right;
|
|
}
|
|
|
|
replace(x, c, t);
|
|
c->left->parent = t;
|
|
t->colored = c->colored;
|
|
t->left = c->left;
|
|
}
|
|
|
|
if (!s) fixup(x, n);
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
|
|
void libcdsb_builtin_rbtree_node_fixup(rbnode_t** x, rbnode_t* n) {
|
|
rbdir_t d[2];
|
|
rbnode_t *u, *p, *gp;
|
|
|
|
while (n->parent->colored) {
|
|
p = n->parent;
|
|
gp = p->parent;
|
|
d[0] = (gp->right == p) ? RBD_LEFT : RBD_RIGHT;
|
|
u = rbdir_dir(gp, d[0]);
|
|
|
|
if (rbdir_dir(p, d[0]) == n) {
|
|
d[1] = (d[0] == RBD_LEFT) ? RBD_RIGHT : RBD_LEFT;
|
|
} else d[1] = 0;
|
|
|
|
if (u->colored) {
|
|
u->colored = 0;
|
|
p->colored = 0;
|
|
gp->colored = 1;
|
|
|
|
n = gp;
|
|
} else {
|
|
if (d[1]) {
|
|
rotate(x, n = p, d[1]);
|
|
p = n->parent;
|
|
gp = p->parent;
|
|
}
|
|
p->colored = 0;
|
|
gp->colored = 1;
|
|
|
|
rotate(x, gp, d[0]);
|
|
}
|
|
|
|
if (rbnode_is_root(n)) break;
|
|
}
|
|
|
|
(*x)->colored = 0;
|
|
}
|
|
|
|
|
|
void* libcdsb_builtin_rbtree_node_create(void* v, rbnode_t* p, int c, int n) {
|
|
rbnode_t* x;
|
|
|
|
x = malloc(n);
|
|
|
|
x->left = rbnode_empty;
|
|
x->right = rbnode_empty;
|
|
x->value = v;
|
|
x->colored = c;
|
|
x->parent = p;
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
stack_t libcdsb_builtin_rbtree_iter_inorder(rbnode_t** root, bool reverse) {
|
|
stack_t z, *cur;
|
|
rbnode_t *n;
|
|
|
|
memset(&z, 0, sizeof(z));
|
|
|
|
if (rbnode_is_empty(n = *root))
|
|
return z;
|
|
|
|
while (!rbnode_is_empty(n)) {
|
|
stack_insert(&z, n);
|
|
n = n->left;
|
|
}
|
|
|
|
cur = z.prev;
|
|
z.value = z.prev->value;
|
|
z.prev = z.prev->prev;
|
|
|
|
free(cur);
|
|
|
|
cur = &z;
|
|
|
|
while ((cur = cur->prev)) {
|
|
n = cur->value;
|
|
|
|
if (!rbnode_is_empty(n->right)) {
|
|
n = n->right;
|
|
|
|
while (!rbnode_is_empty(n)) {
|
|
stack_insert(cur, n);
|
|
n = n->left;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reverse)
|
|
stack_reverse(&z);
|
|
|
|
return z;
|
|
}
|
|
|
|
|
|
stack_t libcdsb_builtin_rbtree_iter_preorder(rbnode_t** root, bool reverse) {
|
|
stack_t z, *cur, *next;
|
|
rbnode_t *n;
|
|
|
|
memset(&z, 0, sizeof(z));
|
|
|
|
if (rbnode_is_empty(*root))
|
|
return z;
|
|
|
|
z.value = *root;
|
|
cur = &z;
|
|
|
|
do {
|
|
n = (next = cur)->value;
|
|
|
|
if (!rbnode_is_empty(n->left)) next = stack_insert(cur, n->left);
|
|
if (!rbnode_is_empty(n->right)) stack_insert(next, n->right);
|
|
} while (!is_null(cur = cur->prev));
|
|
|
|
if (reverse)
|
|
stack_reverse(&z);
|
|
|
|
return z;
|
|
}
|
|
|
|
|
|
stack_t libcdsb_builtin_rbtree_iter_postorder(rbnode_t** root, bool reverse) {
|
|
rbnode_t *p, *n;
|
|
stack_t z, *bot;
|
|
|
|
bot = &z;
|
|
z.prev = 0;
|
|
z.value = 0;
|
|
|
|
if (rbnode_is_empty(p = *root))
|
|
return z;
|
|
|
|
goto mid_;
|
|
|
|
do {
|
|
if (n->parent->right != n && !rbnode_is_empty(n->parent->right)) {
|
|
p = n->parent->right;
|
|
do { mid_:
|
|
n = p;
|
|
p = !rbnode_is_empty(p->left) ? p->left : p->right;
|
|
} while (!rbnode_is_empty(p));
|
|
} else n = n->parent;
|
|
|
|
bot = stack_insert(bot, n);
|
|
} while (!rbnode_is_root(n));
|
|
|
|
bot = z.prev;
|
|
z = *bot;
|
|
|
|
free(bot);
|
|
|
|
if (reverse)
|
|
stack_reverse(&z);
|
|
|
|
return z;
|
|
}
|
|
|
|
|
|
stack_t libcdsb_builtin_rbtree_iter_breadth_first(rbnode_t** root, bool reverse) {
|
|
|
|
stack_t z, *top, *bot, *cur;
|
|
rbnode_t* n;
|
|
|
|
memset(&z, 0, sizeof(z));
|
|
|
|
if (rbnode_is_empty(z.value = *root))
|
|
return z;
|
|
|
|
for (top = bot = &z;;) {
|
|
for (cur = bot;;) {
|
|
|
|
n = top->value;
|
|
|
|
if (!rbnode_is_empty(n->left)) cur = stack_insert(cur, n->left);
|
|
if (!rbnode_is_empty(n->right)) cur = stack_insert(cur, n->right);
|
|
|
|
if (top == bot) {
|
|
top = top->prev;
|
|
break;
|
|
} else top = top->prev;
|
|
}
|
|
|
|
if (!is_null(top)) {
|
|
while (!is_null(bot->prev)) bot = bot->prev;
|
|
} else break;
|
|
}
|
|
|
|
if (reverse)
|
|
stack_reverse(&z);
|
|
|
|
return z;
|
|
}
|