sonic-forest
Version:
High-performance (binary) tree and sorted map implementation (AVL, Splay, Radix, Red-Black)
274 lines (273 loc) • 6.88 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.remove = exports.insertLeft = exports.insertRight = exports.insert = exports.print = void 0;
const swap_1 = require("../util/swap");
const print_1 = require("../util/print");
Object.defineProperty(exports, "print", { enumerable: true, get: function () { return print_1.print; } });
const insert = (root, n, comparator) => {
if (!root)
return (n.b = true), n;
const key = n.k;
let curr = root;
let next = undefined;
let cmp = 0;
while ((next = ((cmp = comparator(key, curr.k)) < 0 ? curr.l : curr.r)))
curr = next;
return (cmp < 0 ? (0, exports.insertLeft)(root, n, curr) : (0, exports.insertRight)(root, n, curr));
};
exports.insert = insert;
const insertRight = (root, n, p) => {
const g = p.p;
p.r = n;
n.p = p;
if (p.b || !g)
return root;
const top = rRebalance(n, p, g);
return top.p ? root : top;
};
exports.insertRight = insertRight;
const insertLeft = (root, n, p) => {
const g = p.p;
p.l = n;
n.p = p;
if (p.b || !g)
return root;
const top = lRebalance(n, p, g);
return top.p ? root : top;
};
exports.insertLeft = insertLeft;
const rRebalance = (n, p, g) => {
const gl = g.l;
const zigzag = gl === p;
const u = zigzag ? g.r : gl;
const uncleIsBlack = !u || u.b;
if (uncleIsBlack) {
g.b = false;
if (zigzag) {
lrRotate(g, p, n);
n.b = true;
return n;
}
p.b = true;
rRotate(g, p);
return p;
}
return recolor(p, g, u);
};
const lRebalance = (n, p, g) => {
const gr = g.r;
const zigzag = gr === p;
const u = zigzag ? g.l : gr;
const uncleIsBlack = !u || u.b;
if (uncleIsBlack) {
g.b = false;
if (zigzag) {
rlRotate(g, p, n);
n.b = true;
return n;
}
p.b = true;
lRotate(g, p);
return p;
}
return recolor(p, g, u);
};
const recolor = (p, g, u) => {
p.b = true;
if (u)
u.b = true;
const gg = g.p;
if (gg) {
g.b = false;
if (gg.b)
return g;
}
else {
g.b = true;
return g;
}
const ggg = gg.p;
if (!ggg)
return gg;
return gg.l === g ? lRebalance(g, gg, ggg) : rRebalance(g, gg, ggg);
};
const lRotate = (n, nl) => {
const p = n.p;
const nlr = nl.r;
((nl.r = n).l = nlr) && (nlr.p = n);
((n.p = nl).p = p) && (p.l === n ? (p.l = nl) : (p.r = nl));
};
const rRotate = (n, nr) => {
const p = n.p;
const nrl = nr.l;
((nr.l = n).r = nrl) && (nrl.p = n);
((n.p = nr).p = p) && (p.l === n ? (p.l = nr) : (p.r = nr));
};
const lrRotate = (g, p, n) => {
const gg = g.p;
const nl = n.l;
const nr = n.r;
gg && (gg.l === g ? (gg.l = n) : (gg.r = n));
n.p = gg;
n.l = p;
n.r = g;
p.p = g.p = n;
(p.r = nl) && (nl.p = p);
(g.l = nr) && (nr.p = g);
};
const rlRotate = (g, p, n) => {
const gg = g.p;
const nl = n.l;
const nr = n.r;
gg && (gg.l === g ? (gg.l = n) : (gg.r = n));
n.p = gg;
n.l = g;
n.r = p;
g.p = p.p = n;
(g.r = nl) && (nl.p = g);
(p.l = nr) && (nr.p = p);
};
const remove = (root, n) => {
const originalNode = n;
const r = n.r;
const l = n.l;
let child;
if (r) {
let inOrderSuccessor = r;
if (inOrderSuccessor)
while (true) {
const next = inOrderSuccessor.l;
if (next)
inOrderSuccessor = next;
else
break;
}
n = inOrderSuccessor;
child = n.r;
}
else if (!n.p) {
if (l) {
l.b = true;
l.p = undefined;
}
return l;
}
else {
child = r || l;
}
if (n !== originalNode) {
originalNode.k = n.k;
originalNode.v = n.v;
const b = n.b;
n.b = originalNode.b;
originalNode.b = b;
root = (0, swap_1.swap)(root, originalNode, n);
n = originalNode;
}
if (child) {
const p = n.p;
child.p = p;
if (p.l === n)
p.l = child;
else
p.r = child;
if (!child.b)
child.b = true;
else
root = correctDoubleBlack(root, child);
}
else {
if (n.b)
root = correctDoubleBlack(root, n);
const p2 = n.p;
if (p2) {
if (n === p2.l)
p2.l = undefined;
else
p2.r = undefined;
}
else {
n.b = true;
return n;
}
}
return root;
};
exports.remove = remove;
const correctDoubleBlack = (root, n) => {
LOOP: while (true) {
const p = n.p;
if (!p)
return n;
const pl = p.l;
const isLeftChild = n === pl;
let s = (isLeftChild ? p.r : pl);
const sl = s.l;
if (s && !s.b && (!sl || sl.b)) {
const sr = s.r;
if (!sr || sr.b) {
if (isLeftChild)
rRotate(p, s);
else
lRotate(p, s);
p.b = false;
s.b = true;
if (!s.p)
root = s;
}
}
if (p.b && s.b && (!sl || sl.b)) {
const sr = s.r;
if (!sr || sr.b) {
s.b = false;
n = p;
continue LOOP;
}
}
if (!p.b) {
const pl = p.l;
s = (n === pl ? p.r : pl);
const sl = s.l;
if (s.b && (!sl || sl.b)) {
const sr = s.r;
if (!sr || sr.b) {
const sr = s.r;
if (!sr || sr.b) {
s.b = false;
p.b = true;
return root;
}
}
}
}
if (s.b) {
const sl = s.l;
const sr = s.r;
if (n === p.l && (!sr || sr.b) && sl && !sl.b) {
sl.b = true;
s.b = false;
lRotate(s, sl);
}
else if (n === p.r && (!sl || sl.b) && sr && !sr.b) {
sr.b = true;
s.b = false;
rRotate(s, sr);
}
if (!s.p)
return s;
const pl = p.l;
s = (n === pl ? p.r : pl);
}
s.b = p.b;
p.b = true;
if (n === p.l) {
s.r.b = true;
rRotate(p, s);
}
else {
s.l.b = true;
lRotate(p, s);
}
return s.p ? root : s;
}
};