You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.2 KiB
238 lines
5.2 KiB
function RedBlackTree() {
|
|
this._ = null; // root node
|
|
}
|
|
|
|
export function RedBlackNode(node) {
|
|
node.U = // parent node
|
|
node.C = // color - true for red, false for black
|
|
node.L = // left node
|
|
node.R = // right node
|
|
node.P = // previous node
|
|
node.N = null; // next node
|
|
}
|
|
|
|
RedBlackTree.prototype = {
|
|
constructor: RedBlackTree,
|
|
|
|
insert: function(after, node) {
|
|
var parent, grandpa, uncle;
|
|
|
|
if (after) {
|
|
node.P = after;
|
|
node.N = after.N;
|
|
if (after.N) after.N.P = node;
|
|
after.N = node;
|
|
if (after.R) {
|
|
after = after.R;
|
|
while (after.L) after = after.L;
|
|
after.L = node;
|
|
} else {
|
|
after.R = node;
|
|
}
|
|
parent = after;
|
|
} else if (this._) {
|
|
after = RedBlackFirst(this._);
|
|
node.P = null;
|
|
node.N = after;
|
|
after.P = after.L = node;
|
|
parent = after;
|
|
} else {
|
|
node.P = node.N = null;
|
|
this._ = node;
|
|
parent = null;
|
|
}
|
|
node.L = node.R = null;
|
|
node.U = parent;
|
|
node.C = true;
|
|
|
|
after = node;
|
|
while (parent && parent.C) {
|
|
grandpa = parent.U;
|
|
if (parent === grandpa.L) {
|
|
uncle = grandpa.R;
|
|
if (uncle && uncle.C) {
|
|
parent.C = uncle.C = false;
|
|
grandpa.C = true;
|
|
after = grandpa;
|
|
} else {
|
|
if (after === parent.R) {
|
|
RedBlackRotateLeft(this, parent);
|
|
after = parent;
|
|
parent = after.U;
|
|
}
|
|
parent.C = false;
|
|
grandpa.C = true;
|
|
RedBlackRotateRight(this, grandpa);
|
|
}
|
|
} else {
|
|
uncle = grandpa.L;
|
|
if (uncle && uncle.C) {
|
|
parent.C = uncle.C = false;
|
|
grandpa.C = true;
|
|
after = grandpa;
|
|
} else {
|
|
if (after === parent.L) {
|
|
RedBlackRotateRight(this, parent);
|
|
after = parent;
|
|
parent = after.U;
|
|
}
|
|
parent.C = false;
|
|
grandpa.C = true;
|
|
RedBlackRotateLeft(this, grandpa);
|
|
}
|
|
}
|
|
parent = after.U;
|
|
}
|
|
this._.C = false;
|
|
},
|
|
|
|
remove: function(node) {
|
|
if (node.N) node.N.P = node.P;
|
|
if (node.P) node.P.N = node.N;
|
|
node.N = node.P = null;
|
|
|
|
var parent = node.U,
|
|
sibling,
|
|
left = node.L,
|
|
right = node.R,
|
|
next,
|
|
red;
|
|
|
|
if (!left) next = right;
|
|
else if (!right) next = left;
|
|
else next = RedBlackFirst(right);
|
|
|
|
if (parent) {
|
|
if (parent.L === node) parent.L = next;
|
|
else parent.R = next;
|
|
} else {
|
|
this._ = next;
|
|
}
|
|
|
|
if (left && right) {
|
|
red = next.C;
|
|
next.C = node.C;
|
|
next.L = left;
|
|
left.U = next;
|
|
if (next !== right) {
|
|
parent = next.U;
|
|
next.U = node.U;
|
|
node = next.R;
|
|
parent.L = node;
|
|
next.R = right;
|
|
right.U = next;
|
|
} else {
|
|
next.U = parent;
|
|
parent = next;
|
|
node = next.R;
|
|
}
|
|
} else {
|
|
red = node.C;
|
|
node = next;
|
|
}
|
|
|
|
if (node) node.U = parent;
|
|
if (red) return;
|
|
if (node && node.C) { node.C = false; return; }
|
|
|
|
do {
|
|
if (node === this._) break;
|
|
if (node === parent.L) {
|
|
sibling = parent.R;
|
|
if (sibling.C) {
|
|
sibling.C = false;
|
|
parent.C = true;
|
|
RedBlackRotateLeft(this, parent);
|
|
sibling = parent.R;
|
|
}
|
|
if ((sibling.L && sibling.L.C)
|
|
|| (sibling.R && sibling.R.C)) {
|
|
if (!sibling.R || !sibling.R.C) {
|
|
sibling.L.C = false;
|
|
sibling.C = true;
|
|
RedBlackRotateRight(this, sibling);
|
|
sibling = parent.R;
|
|
}
|
|
sibling.C = parent.C;
|
|
parent.C = sibling.R.C = false;
|
|
RedBlackRotateLeft(this, parent);
|
|
node = this._;
|
|
break;
|
|
}
|
|
} else {
|
|
sibling = parent.L;
|
|
if (sibling.C) {
|
|
sibling.C = false;
|
|
parent.C = true;
|
|
RedBlackRotateRight(this, parent);
|
|
sibling = parent.L;
|
|
}
|
|
if ((sibling.L && sibling.L.C)
|
|
|| (sibling.R && sibling.R.C)) {
|
|
if (!sibling.L || !sibling.L.C) {
|
|
sibling.R.C = false;
|
|
sibling.C = true;
|
|
RedBlackRotateLeft(this, sibling);
|
|
sibling = parent.L;
|
|
}
|
|
sibling.C = parent.C;
|
|
parent.C = sibling.L.C = false;
|
|
RedBlackRotateRight(this, parent);
|
|
node = this._;
|
|
break;
|
|
}
|
|
}
|
|
sibling.C = true;
|
|
node = parent;
|
|
parent = parent.U;
|
|
} while (!node.C);
|
|
|
|
if (node) node.C = false;
|
|
}
|
|
};
|
|
|
|
function RedBlackRotateLeft(tree, node) {
|
|
var p = node,
|
|
q = node.R,
|
|
parent = p.U;
|
|
|
|
if (parent) {
|
|
if (parent.L === p) parent.L = q;
|
|
else parent.R = q;
|
|
} else {
|
|
tree._ = q;
|
|
}
|
|
|
|
q.U = parent;
|
|
p.U = q;
|
|
p.R = q.L;
|
|
if (p.R) p.R.U = p;
|
|
q.L = p;
|
|
}
|
|
|
|
function RedBlackRotateRight(tree, node) {
|
|
var p = node,
|
|
q = node.L,
|
|
parent = p.U;
|
|
|
|
if (parent) {
|
|
if (parent.L === p) parent.L = q;
|
|
else parent.R = q;
|
|
} else {
|
|
tree._ = q;
|
|
}
|
|
|
|
q.U = parent;
|
|
p.U = q;
|
|
p.L = q.R;
|
|
if (p.L) p.L.U = p;
|
|
q.R = p;
|
|
}
|
|
|
|
function RedBlackFirst(node) {
|
|
while (node.L) node = node.L;
|
|
return node;
|
|
}
|
|
|
|
export default RedBlackTree;
|