330 lines
6.1 KiB
C
330 lines
6.1 KiB
C
// ::DataStructures::Globals::Start::
|
|
|
|
RBNode RB_NIL = { .color = RB_BLACK };
|
|
|
|
// ::DataStructures::Globals::End::
|
|
|
|
|
|
|
|
// ::DataStructures::RedBlackTree::Functions::Start::
|
|
|
|
static void CreateRBTree(RBTree *tree)
|
|
{
|
|
Assert(tree != NULL, "RBTree is null");
|
|
RB_NIL.right = RB_NIL.left = RB_NIL.parent = &RB_NIL;
|
|
|
|
tree->root = &RB_NIL;
|
|
tree->nil = &RB_NIL;
|
|
}
|
|
|
|
static void RBTreeInsert(RBTree *tree, RBNode *node)
|
|
{
|
|
node->left = node->right = tree->nil;
|
|
node->color = RB_RED;
|
|
|
|
if (tree->root == tree->nil)
|
|
{
|
|
node->color = RB_BLACK;
|
|
node->parent = tree->nil;
|
|
tree->root = node;
|
|
}
|
|
else
|
|
{
|
|
RBNode *curr_node = tree->root;
|
|
while (true)
|
|
{
|
|
Assert(curr_node != tree->nil, "Current Node is NIL");
|
|
|
|
if (curr_node->value < node->value)
|
|
{
|
|
if (curr_node->right == tree->nil)
|
|
{
|
|
node->parent = curr_node;
|
|
curr_node->right = node;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
curr_node = curr_node->right;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (curr_node->left == tree->nil)
|
|
{
|
|
node->parent = curr_node;
|
|
curr_node->left = node;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
curr_node = curr_node->left;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (node->parent->color != RB_BLACK)
|
|
RBTreeCorrect(tree, node);
|
|
}
|
|
|
|
static void RBTreeCorrect(RBTree *tree, RBNode *node)
|
|
{
|
|
RBNode *gp = node->parent->parent;
|
|
RBNode *p = node->parent;
|
|
do
|
|
{
|
|
if (node == tree->root)
|
|
{
|
|
node->color = RB_BLACK;
|
|
break;
|
|
}
|
|
|
|
if (gp == tree->nil)
|
|
{
|
|
p->color = RB_BLACK;
|
|
break;
|
|
}
|
|
|
|
RBNodeDir dir = NodeDir(p);
|
|
RBNode *unc = gp->child[1 - dir];
|
|
if (unc == tree->nil || unc->color == RB_BLACK)
|
|
{
|
|
if (node == p->child[1 - dir])
|
|
{
|
|
RBTreeRotate(tree, p, dir);
|
|
node = p;
|
|
p = gp->child[dir];
|
|
}
|
|
|
|
RBTreeRotate(tree, gp, 1 - dir);
|
|
p->color = RB_BLACK;
|
|
gp->color = RB_RED;
|
|
break;
|
|
}
|
|
|
|
p->color = RB_BLACK;
|
|
unc->color = RB_BLACK;
|
|
gp->color = RB_RED;
|
|
node = gp;
|
|
gp = node->parent->parent;
|
|
} while ((p = node->parent));
|
|
}
|
|
|
|
static void RBTreeDelete(RBTree *tree, i32 value)
|
|
{
|
|
RBNode *node = NULL;
|
|
Assert(RBTreeSearch(tree, value, &node), "Unable to find node in RBTreeDelete");
|
|
|
|
if (node == tree->root && node->left == tree->nil && node->right == tree->nil)
|
|
{
|
|
tree->root = tree->nil;
|
|
}
|
|
else if (node->left != tree->nil && node->right != tree->nil)
|
|
{
|
|
RBNode *ln = node->right;
|
|
|
|
while (ln->left != tree->nil)
|
|
ln = ln->left;
|
|
|
|
node->value = ln->value;
|
|
node->data = ln->data;
|
|
|
|
if (node->right == ln)
|
|
node->right = tree->nil;
|
|
else
|
|
ln->parent->left = tree->nil;
|
|
|
|
ln->parent = tree->nil;
|
|
}
|
|
else if (node->color == RB_BLACK && node->left != tree->nil)
|
|
{
|
|
node->value = node->left->value;
|
|
node->data = node->left->data;
|
|
node->left = tree->nil;
|
|
}
|
|
else if (node->color == RB_BLACK && node->right != tree->nil)
|
|
{
|
|
node->value = node->right->value;
|
|
node->data = node->right->data;
|
|
node->right = tree->nil;
|
|
}
|
|
else if (node->color == RB_RED && node->right == tree->nil && node->left == tree->nil)
|
|
{
|
|
RBNodeDir dir = NodeDir(node);
|
|
node->parent->child[dir] = tree->nil;
|
|
}
|
|
else
|
|
{
|
|
RBNode *p = node->parent;
|
|
RBNodeColor col = node->color;
|
|
RBNode *s, *cn, *dn;
|
|
|
|
RBNodeDir dir = NodeDir(node);
|
|
p->child[dir] = tree->nil;
|
|
|
|
goto start_deletion;
|
|
|
|
do
|
|
{
|
|
dir = NodeDir(node);
|
|
start_deletion:
|
|
s = p->child[1 - dir];
|
|
dn = s->child[1 - dir];
|
|
cn = s->child[dir];
|
|
|
|
if (s->color == RB_RED)
|
|
{
|
|
RBTreeRotate(tree, p, dir);
|
|
p->color = RB_RED;
|
|
s->color = RB_BLACK;
|
|
s = cn;
|
|
|
|
dn = s->child[1 - dir];
|
|
if (dn->color == RB_RED)
|
|
goto rotate_sibling;
|
|
cn = s->child[dir];
|
|
if (cn->color == RB_RED)
|
|
goto rotate_parent;
|
|
|
|
s->color = RB_RED;
|
|
p->color = RB_BLACK;
|
|
return;
|
|
}
|
|
|
|
if (dn->color == RB_RED)
|
|
goto rotate_parent;
|
|
|
|
if (cn->color == RB_RED)
|
|
goto rotate_sibling;
|
|
|
|
if (p->color == RB_RED)
|
|
{
|
|
s->color = RB_RED;
|
|
p->color = RB_BLACK;
|
|
return;
|
|
}
|
|
|
|
if (p == tree->nil)
|
|
return;
|
|
|
|
s->color = RB_RED;
|
|
node = p;
|
|
} while ((p = node->parent));
|
|
|
|
rotate_sibling:
|
|
RBTreeRotate(tree, s, 1 - dir);
|
|
s->color = RB_RED;
|
|
cn->color = RB_BLACK;
|
|
dn = s;
|
|
s = cn;
|
|
|
|
rotate_parent:
|
|
RBTreeRotate(tree, p, dir);
|
|
s->color = p->color;
|
|
p->color = RB_BLACK;
|
|
dn->color = RB_BLACK;
|
|
}
|
|
}
|
|
|
|
static b32 RBTreeSearch(RBTree *tree, i32 value, RBNode **out_node)
|
|
{
|
|
if (tree->root == tree->nil) return false;
|
|
|
|
b32 found = false;
|
|
RBNode *node = tree->root;
|
|
|
|
while (true)
|
|
{
|
|
if (node->value == value)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (node == tree->nil)
|
|
break;
|
|
|
|
if (node->value < value)
|
|
node = node->right;
|
|
else
|
|
node = node->left;
|
|
}
|
|
|
|
if (found)
|
|
*out_node = node;
|
|
|
|
return found;
|
|
}
|
|
|
|
static inline void RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node)
|
|
{
|
|
if (node->parent == tree->nil)
|
|
tree->root = placed_node;
|
|
else if (node == node->parent->left)
|
|
node->parent->left = placed_node;
|
|
else
|
|
node->parent->right = placed_node;
|
|
|
|
placed_node->parent = node->parent;
|
|
}
|
|
|
|
static void RBTreeRotate(RBTree *tree, RBNode *node, RBNodeDir dir)
|
|
{
|
|
RBNode *p = node->parent;
|
|
RBNode *root = node->child[1 - dir];
|
|
RBNode *child = root->child[dir];
|
|
|
|
node->child[1 - dir] = child;
|
|
|
|
if (child != tree->nil)
|
|
child->parent = node;
|
|
|
|
root->child[dir] = node;
|
|
root->parent = p;
|
|
node->parent = root;
|
|
|
|
if (p != tree->nil)
|
|
p->child[node == p->right] = root;
|
|
else
|
|
tree->root = root;
|
|
}
|
|
|
|
static void RBTreeLeftRotate(RBTree *tree, RBNode *node)
|
|
{
|
|
RBNode *right = node->right;
|
|
if (right->left != tree->nil)
|
|
node->right = right->left;
|
|
|
|
if (node->parent == tree->nil)
|
|
tree->root = right;
|
|
else if (node->parent->left == node)
|
|
node->parent->left = right;
|
|
else
|
|
node->parent->right = right;
|
|
|
|
right->parent = node->parent;
|
|
right->left = node;
|
|
node->parent = right;
|
|
}
|
|
|
|
static void RBTreeRightRotate(RBTree *tree, RBNode *node)
|
|
{
|
|
RBNode *left = node->left;
|
|
if (left->right != tree->nil)
|
|
node->left = left->right;
|
|
|
|
if (node->parent == tree->nil)
|
|
tree->root = left;
|
|
else if (node->parent->left == node)
|
|
node->parent->left = left;
|
|
else
|
|
node->parent->right = left;
|
|
|
|
left->parent = node->parent;
|
|
left->right = node;
|
|
node->parent = left;
|
|
}
|
|
|
|
// ::DataStructures::RedBlackTree::Functions::Start::
|