314 lines
7.7 KiB
C
314 lines
7.7 KiB
C
#include "rbt.h"
|
|
|
|
static bool isRed(const RbtNode* n)
|
|
{
|
|
return n != nullptr && n->red;
|
|
}
|
|
|
|
static void setChild(RbTree* t, RbtNode* parent, RbtNode* oldChild, RbtNode* newChild)
|
|
{
|
|
if (parent == nullptr)
|
|
t->root = newChild;
|
|
else if (parent->left == oldChild)
|
|
parent->left = newChild;
|
|
else
|
|
parent->right = newChild;
|
|
}
|
|
|
|
static void rotateLeft(RbTree* t, RbtNode* x)
|
|
{
|
|
RbtNode* y = x->right;
|
|
x->right = y->left;
|
|
if (y->left != nullptr)
|
|
y->left->parent = x;
|
|
y->parent = x->parent;
|
|
setChild(t, x->parent, x, y);
|
|
y->left = x;
|
|
x->parent = y;
|
|
}
|
|
|
|
static void rotateRight(RbTree* t, RbtNode* x)
|
|
{
|
|
RbtNode* y = x->left;
|
|
x->left = y->right;
|
|
if (y->right != nullptr)
|
|
y->right->parent = x;
|
|
y->parent = x->parent;
|
|
setChild(t, x->parent, x, y);
|
|
y->right = x;
|
|
x->parent = y;
|
|
}
|
|
|
|
static void insertFixup(RbTree* t, RbtNode* z)
|
|
{
|
|
while (isRed(z->parent)) {
|
|
RbtNode* parent = z->parent;
|
|
RbtNode* grandparent = parent->parent;
|
|
|
|
if (parent == grandparent->left) {
|
|
RbtNode* uncle = grandparent->right;
|
|
if (isRed(uncle)) {
|
|
parent->red = false;
|
|
uncle->red = false;
|
|
grandparent->red = true;
|
|
z = grandparent;
|
|
} else {
|
|
if (z == parent->right) {
|
|
z = parent;
|
|
rotateLeft(t, z);
|
|
parent = z->parent;
|
|
}
|
|
parent->red = false;
|
|
grandparent->red = true;
|
|
rotateRight(t, grandparent);
|
|
}
|
|
} else {
|
|
RbtNode* uncle = grandparent->left;
|
|
if (isRed(uncle)) {
|
|
parent->red = false;
|
|
uncle->red = false;
|
|
grandparent->red = true;
|
|
z = grandparent;
|
|
} else {
|
|
if (z == parent->left) {
|
|
z = parent;
|
|
rotateRight(t, z);
|
|
parent = z->parent;
|
|
}
|
|
parent->red = false;
|
|
grandparent->red = true;
|
|
rotateLeft(t, grandparent);
|
|
}
|
|
}
|
|
}
|
|
t->root->red = false;
|
|
}
|
|
|
|
static void removeFixup(RbTree* t, RbtNode* x, RbtNode* xParent)
|
|
{
|
|
while (x != t->root && !isRed(x)) {
|
|
if (x == xParent->left) {
|
|
RbtNode* w = xParent->right;
|
|
if (isRed(w)) {
|
|
w->red = false;
|
|
xParent->red = true;
|
|
rotateLeft(t, xParent);
|
|
w = xParent->right;
|
|
}
|
|
if (!isRed(w->left) && !isRed(w->right)) {
|
|
w->red = true;
|
|
x = xParent;
|
|
xParent = x->parent;
|
|
} else {
|
|
if (!isRed(w->right)) {
|
|
if (w->left != nullptr)
|
|
w->left->red = false;
|
|
w->red = true;
|
|
rotateRight(t, w);
|
|
w = xParent->right;
|
|
}
|
|
w->red = xParent->red;
|
|
xParent->red = false;
|
|
if (w->right != nullptr)
|
|
w->right->red = false;
|
|
rotateLeft(t, xParent);
|
|
x = t->root;
|
|
xParent = nullptr;
|
|
}
|
|
} else {
|
|
RbtNode* w = xParent->left;
|
|
if (isRed(w)) {
|
|
w->red = false;
|
|
xParent->red = true;
|
|
rotateRight(t, xParent);
|
|
w = xParent->left;
|
|
}
|
|
if (!isRed(w->left) && !isRed(w->right)) {
|
|
w->red = true;
|
|
x = xParent;
|
|
xParent = x->parent;
|
|
} else {
|
|
if (!isRed(w->left)) {
|
|
if (w->right != nullptr)
|
|
w->right->red = false;
|
|
w->red = true;
|
|
rotateLeft(t, w);
|
|
w = xParent->left;
|
|
}
|
|
w->red = xParent->red;
|
|
xParent->red = false;
|
|
if (w->left != nullptr)
|
|
w->left->red = false;
|
|
rotateRight(t, xParent);
|
|
x = t->root;
|
|
xParent = nullptr;
|
|
}
|
|
}
|
|
}
|
|
if (x != nullptr)
|
|
x->red = false;
|
|
}
|
|
|
|
void rbtInit(RbTree* t)
|
|
{
|
|
t->root = nullptr;
|
|
t->count = 0;
|
|
}
|
|
|
|
bool rbtInsert(RbTree* t, RbtNode* node, RbtCompareFn compare)
|
|
{
|
|
RbtNode* parent = nullptr;
|
|
RbtNode* cur = t->root;
|
|
bool goLeft = false;
|
|
|
|
while (cur != nullptr) {
|
|
int c = compare(node, cur);
|
|
if (c == 0)
|
|
return false;
|
|
parent = cur;
|
|
goLeft = c < 0;
|
|
cur = goLeft ? cur->left : cur->right;
|
|
}
|
|
|
|
node->left = nullptr;
|
|
node->right = nullptr;
|
|
node->parent = parent;
|
|
node->red = true;
|
|
|
|
if (parent == nullptr)
|
|
t->root = node;
|
|
else if (goLeft)
|
|
parent->left = node;
|
|
else
|
|
parent->right = node;
|
|
|
|
t->count++;
|
|
insertFixup(t, node);
|
|
return true;
|
|
}
|
|
|
|
void rbtRemove(RbTree* t, RbtNode* z)
|
|
{
|
|
RbtNode* y = z;
|
|
bool yOriginalRed = y->red;
|
|
RbtNode* x;
|
|
RbtNode* xParent;
|
|
|
|
if (z->left == nullptr) {
|
|
x = z->right;
|
|
xParent = z->parent;
|
|
setChild(t, z->parent, z, z->right);
|
|
if (z->right != nullptr)
|
|
z->right->parent = z->parent;
|
|
} else if (z->right == nullptr) {
|
|
x = z->left;
|
|
xParent = z->parent;
|
|
setChild(t, z->parent, z, z->left);
|
|
if (z->left != nullptr)
|
|
z->left->parent = z->parent;
|
|
} else {
|
|
y = z->right;
|
|
while (y->left != nullptr)
|
|
y = y->left;
|
|
yOriginalRed = y->red;
|
|
x = y->right;
|
|
|
|
if (y->parent == z) {
|
|
xParent = y;
|
|
} else {
|
|
xParent = y->parent;
|
|
setChild(t, y->parent, y, y->right);
|
|
if (y->right != nullptr)
|
|
y->right->parent = y->parent;
|
|
y->right = z->right;
|
|
y->right->parent = y;
|
|
}
|
|
|
|
setChild(t, z->parent, z, y);
|
|
y->parent = z->parent;
|
|
y->left = z->left;
|
|
y->left->parent = y;
|
|
y->red = z->red;
|
|
}
|
|
|
|
t->count--;
|
|
if (!yOriginalRed)
|
|
removeFixup(t, x, xParent);
|
|
}
|
|
|
|
RbtNode* rbtFind(const RbTree* t, const void* key, RbtLookupFn lookup)
|
|
{
|
|
RbtNode* cur = t->root;
|
|
while (cur != nullptr) {
|
|
int c = lookup(key, cur);
|
|
if (c == 0)
|
|
return cur;
|
|
cur = c < 0 ? cur->left : cur->right;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
RbtNode* rbtFirst(const RbTree* t)
|
|
{
|
|
RbtNode* n = t->root;
|
|
if (n == nullptr)
|
|
return nullptr;
|
|
while (n->left != nullptr)
|
|
n = n->left;
|
|
return n;
|
|
}
|
|
|
|
RbtNode* rbtLast(const RbTree* t)
|
|
{
|
|
RbtNode* n = t->root;
|
|
if (n == nullptr)
|
|
return nullptr;
|
|
while (n->right != nullptr)
|
|
n = n->right;
|
|
return n;
|
|
}
|
|
|
|
RbtNode* rbtNext(const RbtNode* node)
|
|
{
|
|
if (node->right != nullptr) {
|
|
RbtNode* n = node->right;
|
|
while (n->left != nullptr)
|
|
n = n->left;
|
|
return n;
|
|
}
|
|
RbtNode* n = (RbtNode*)node;
|
|
RbtNode* parent = n->parent;
|
|
while (parent != nullptr && n == parent->right) {
|
|
n = parent;
|
|
parent = parent->parent;
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
RbtNode* rbtPrev(const RbtNode* node)
|
|
{
|
|
if (node->left != nullptr) {
|
|
RbtNode* n = node->left;
|
|
while (n->right != nullptr)
|
|
n = n->right;
|
|
return n;
|
|
}
|
|
RbtNode* n = (RbtNode*)node;
|
|
RbtNode* parent = n->parent;
|
|
while (parent != nullptr && n == parent->left) {
|
|
n = parent;
|
|
parent = parent->parent;
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
usize rbtCount(const RbTree* t)
|
|
{
|
|
return t->count;
|
|
}
|
|
|
|
bool rbtIsEmpty(const RbTree* t)
|
|
{
|
|
return t->root == nullptr;
|
|
}
|