diff --git a/src/rbt.c b/src/rbt.c new file mode 100644 index 0000000..8afc949 --- /dev/null +++ b/src/rbt.c @@ -0,0 +1,157 @@ +#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; +} +