- Fixed rb-tree violations
This commit is contained in:
@@ -41,23 +41,11 @@
|
|||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
|
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
|
||||||
// https://www.geeksforgeeks.org/dsa/insertion-in-red-black-tree/
|
// https://www.geeksforgeeks.org/dsa/insertion-in-red-black-tree/
|
||||||
|
// https://github.com/anandarao/Red-Black-Tree/blob/master/RBTree.cpp
|
||||||
|
|
||||||
// Uncertain how I managed to do this, but this data structure has
|
// After rewriting the _fix_insert and _fix_erase functions the performance decreased significantly in the lower end
|
||||||
// A 33%-100% performance increase over std::set when running Dijkstra's
|
// but now in the higher end it remains consistent. Something I was doing was disturbing both the rb-tree and bst tree
|
||||||
//
|
// properties, now that is fixed. I'll see about optimizing more in the future.
|
||||||
// Guesses:
|
|
||||||
// -> I likely make some assumptions that std::set doesn't
|
|
||||||
// -> Cache locality
|
|
||||||
// -> Simplified rotation and coloring logic
|
|
||||||
//
|
|
||||||
// Some of the implementations I have seen have multiple levels
|
|
||||||
// of if statements based on directionality which causes branching.
|
|
||||||
// I use const-expressions that reduce down to cmov instructions
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// I ran some more performance tests, and it does not hold up well at the larger end of things.
|
|
||||||
// I think something with the balancing on insertion is a tad messed up.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -376,19 +364,12 @@ protected:
|
|||||||
// Then we just need to handle splitting a 4-node
|
// Then we just need to handle splitting a 4-node
|
||||||
constexpr void _fix_insert(size_t n) {
|
constexpr void _fix_insert(size_t n) {
|
||||||
size_t p = parent(n);
|
size_t p = parent(n);
|
||||||
while (color(p) != black) {
|
while (n != _root && color(n) == red && color(p) == red) {
|
||||||
size_t g = parent(p);
|
size_t g = parent(p);
|
||||||
size_t u = sibling(p);
|
bool d = n == right(p);
|
||||||
size_t d = direction(n);
|
bool r = p == right(g);
|
||||||
size_t r = direction(p);
|
size_t u = child(g, !r);
|
||||||
|
|
||||||
// Case 4
|
|
||||||
if (g == npos) {
|
|
||||||
_color(p) = black;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split 4 node
|
|
||||||
if (color(u) == red) {
|
if (color(u) == red) {
|
||||||
_recolor(g);
|
_recolor(g);
|
||||||
n = g;
|
n = g;
|
||||||
@@ -396,16 +377,18 @@ protected:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LR & RL case
|
|
||||||
if (d != r) {
|
if (d != r) {
|
||||||
rotate(p, r);
|
rotate(p, r);
|
||||||
|
n = p;
|
||||||
|
p = parent(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LL & RR case
|
|
||||||
rotate(g, not r);
|
rotate(g, not r);
|
||||||
n = grandparent(n);
|
fennec::swap(_color(p), _color(g));
|
||||||
|
n = p;
|
||||||
p = parent(n);
|
p = parent(n);
|
||||||
}
|
}
|
||||||
|
_color(_root) = black;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void _transplant(size_t u, size_t v) {
|
constexpr void _transplant(size_t u, size_t v) {
|
||||||
@@ -443,8 +426,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t _red_child(size_t x) {
|
constexpr size_t _red_child(size_t x) {
|
||||||
size_t l = left(x);
|
size_t l = _left(x);
|
||||||
size_t r = right(x);
|
size_t r = _right(x);
|
||||||
|
|
||||||
if (color(l) == red) {
|
if (color(l) == red) {
|
||||||
return l;
|
return l;
|
||||||
@@ -457,96 +440,89 @@ protected:
|
|||||||
return npos;
|
return npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an implementation based on the C code in
|
|
||||||
// the wikipedia article adapted to this framework
|
|
||||||
constexpr void _fix_erase(size_t n) {
|
constexpr void _fix_erase(size_t n) {
|
||||||
|
if (n == npos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == _root) {
|
||||||
|
_root = npos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t o = n;
|
||||||
size_t p = parent(n);
|
size_t p = parent(n);
|
||||||
size_t s, sc, sf;
|
if (p == npos) {
|
||||||
|
_root = npos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool d = n == right(p);
|
bool d = n == right(p);
|
||||||
|
size_t c = _red_child(n);
|
||||||
|
size_t s = npos;
|
||||||
|
if (_color(n) == red || c != npos) {
|
||||||
|
_child(p, d) = c;
|
||||||
|
if (c != npos) {
|
||||||
|
_parent(c) = p;
|
||||||
|
}
|
||||||
|
_color(c) = black;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_child(p, d) = npos;
|
while (n != _root) {
|
||||||
|
p = _parent(n);
|
||||||
|
d = n == _right(p);
|
||||||
|
s = _child(p, !d);
|
||||||
|
|
||||||
goto start_balance;
|
if (s == npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
if (_color(s) == red) {
|
||||||
d = n == right(p);
|
|
||||||
start_balance:
|
|
||||||
s = child(p, !d);
|
|
||||||
sf = child(s, !d);
|
|
||||||
sc = child(s, d);
|
|
||||||
|
|
||||||
if (color(s) == red) {
|
|
||||||
// Case 3
|
|
||||||
rotate(p, d);
|
|
||||||
_color(p) = red;
|
|
||||||
_color(s) = black;
|
_color(s) = black;
|
||||||
|
_color(p) = red;
|
||||||
// Fix pointers
|
rotate(p, d);
|
||||||
s = sc;
|
continue;
|
||||||
sf = child(s, !d);
|
|
||||||
sc = child(s, d);
|
|
||||||
|
|
||||||
if (color(sf) == red) {
|
|
||||||
goto case_6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color(sc) == red) {
|
|
||||||
goto case_5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 4
|
|
||||||
if (color(p) == red) {
|
|
||||||
if (s != npos) {
|
|
||||||
_color(s) = red;
|
|
||||||
}
|
|
||||||
_color(p) = black;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color(sf) == red) {
|
size_t nc = _child(s, d);
|
||||||
goto case_6;
|
size_t nf = _child(s, !d);
|
||||||
}
|
|
||||||
|
|
||||||
if (color(sc) == red) {
|
if (color(nc) == black && color(nf) == black) {
|
||||||
goto case_5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 4
|
|
||||||
if (color(p) == red) {
|
|
||||||
if (s != npos) {
|
|
||||||
_color(s) = red;
|
|
||||||
}
|
|
||||||
_color(p) = black;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 1
|
|
||||||
if (p == npos) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 2
|
|
||||||
if (s != npos) {
|
|
||||||
_color(s) = red;
|
_color(s) = red;
|
||||||
|
if (_color(p) == red) {
|
||||||
|
_color(p) = black;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n = p;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
n = p;
|
|
||||||
} while ((p = parent(n)) != npos);
|
|
||||||
|
|
||||||
return; //
|
if (color(nf) == black) {
|
||||||
|
_color(nc) = black;
|
||||||
|
_color(s) = red;
|
||||||
|
rotate(s, !d);
|
||||||
|
s = nc;
|
||||||
|
nf = s;
|
||||||
|
}
|
||||||
|
_color(s) = _color(p);
|
||||||
|
_color(p) = black;
|
||||||
|
_color(nf) = black;
|
||||||
|
rotate(p, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case_5:
|
p = parent(o);
|
||||||
rotate(s, !d);
|
if (p != npos) {
|
||||||
_color(s) = red;
|
if (o == _left(p)) {
|
||||||
_color(sc) = black;
|
_left(p) = npos;
|
||||||
sf = s;
|
} else {
|
||||||
s = sc;
|
_right(p) = npos;
|
||||||
|
}
|
||||||
case_6:
|
_color(_root) = black;
|
||||||
rotate(p, d);
|
} else {
|
||||||
_color(s) = color(p);
|
_root = npos;
|
||||||
_color(p) = black;
|
}
|
||||||
_color(sf) = black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void _erase(size_t n) {
|
constexpr void _erase(size_t n) {
|
||||||
@@ -554,19 +530,19 @@ protected:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t l = left(n);
|
size_t l = _left(n);
|
||||||
size_t r = right(n);
|
size_t r = _right(n);
|
||||||
|
|
||||||
// 2 children
|
// 2 children
|
||||||
if (l != npos && r != npos) {
|
if (l != npos && r != npos) {
|
||||||
size_t s = left_most(r);
|
size_t s = left_most(r);
|
||||||
_swap_val(n, s);
|
_swap_val(n, s);
|
||||||
n = s;
|
n = s;
|
||||||
l = left(n);
|
l = _left(n);
|
||||||
r = right(n);
|
r = _right(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t p = parent(n);
|
size_t p = _parent(n);
|
||||||
bool d = n == right(p);
|
bool d = n == right(p);
|
||||||
size_t c = l != npos ? l : r;
|
size_t c = l != npos ? l : r;
|
||||||
|
|
||||||
@@ -589,7 +565,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Single Child, Red, and Root cases
|
// Single Child, Red, and Root cases
|
||||||
if (p == npos || c != npos || color(n) == red) {
|
if (p == npos || c != npos || _color(n) == red) {
|
||||||
if (p != npos) {
|
if (p != npos) {
|
||||||
_child(p, d) = c;
|
_child(p, d) = c;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user