feat: port python code to JS
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
2beb2d9fc7
commit
f5c746b783
5 changed files with 640 additions and 0 deletions
162
avl.js
Normal file
162
avl.js
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
Array.prototype.equals = function(other) {
|
||||||
|
if (this.length != other.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = this.length;
|
||||||
|
while (--i >= 0) {
|
||||||
|
if (this[i] !== other[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function balanceFactor(node) {
|
||||||
|
if (!node) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [left, right] = [nodeRank(node.left), nodeRank(node.right)];
|
||||||
|
return right - left;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRank(node) {
|
||||||
|
let [left, right] = [nodeRank(node.left), nodeRank(node.right)];
|
||||||
|
node.rank = 1 + Math.max(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AVLTree extends RankedTree {
|
||||||
|
isCorrectNode(node, recursive) {
|
||||||
|
if (!node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive = recursive ?? true;
|
||||||
|
|
||||||
|
// FIXME: not enough, must be checked against differences
|
||||||
|
// let bf = balanceFactor(node);
|
||||||
|
// if (bf < -1 || bf > 1) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let differences = nodeDifferences(node);
|
||||||
|
differences.sort();
|
||||||
|
if (!differences.equals([1, 1]) && !differences.equals([1, 2])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !recursive || (this.isCorrectNode(node.left) && this.isCorrectNode(node.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
fix0Child(x, y, z, rotateLeft, rotateRight) {
|
||||||
|
let newRoot = x.parent;
|
||||||
|
|
||||||
|
if (!y || nodeDifference(y) == 2) {
|
||||||
|
newRoot = rotateRight(z);
|
||||||
|
z.demote();
|
||||||
|
} else if (nodeDifference(y) == 1) {
|
||||||
|
rotateLeft(x);
|
||||||
|
newRoot = rotateRight(z);
|
||||||
|
|
||||||
|
y.promote();
|
||||||
|
x.demote();
|
||||||
|
z.demote();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertRebalance(x) {
|
||||||
|
let diffs = nodeDifferences(x.parent).sort();
|
||||||
|
while (x.parent && diffs.equals([0, 1])) {
|
||||||
|
x.parent.promote();
|
||||||
|
x = x.parent;
|
||||||
|
|
||||||
|
diffs = nodeDifferences(x.parent).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rotatingAroundRoot = x.parent.parent == null;
|
||||||
|
let newRoot = x.parent;
|
||||||
|
|
||||||
|
let rankDifference = nodeDifference(x);
|
||||||
|
if (rankDifference != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let xParent = x.parent;
|
||||||
|
|
||||||
|
if (rankDifference == 0 && x.parent.left === x) {
|
||||||
|
newRoot = this.fix0Child(
|
||||||
|
x, x.right, xParent, rotateLeft, rotateRight
|
||||||
|
);
|
||||||
|
} else if (rankDifference == 0 && x.parent.right === x) {
|
||||||
|
newRoot = this.fix0Child(
|
||||||
|
x, x.left, xParent, rotateRight, rotateLeft
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotatingAroundRoot) {
|
||||||
|
this.root = newRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRotate(x, y, leaning, rotatingAroundRoot, rotateLeft, rotateRight) {
|
||||||
|
let newRoot = x;
|
||||||
|
|
||||||
|
let factor = balanceFactor(y);
|
||||||
|
switch (factor) {
|
||||||
|
case 0:
|
||||||
|
case leaning:
|
||||||
|
newRoot = rotateLeft(x);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rotateRight(y);
|
||||||
|
newRoot = rotateLeft(x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[newRoot.left, newRoot.right, newRoot].filter(x => x).forEach(n => {
|
||||||
|
updateRank(n)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rotatingAroundRoot) {
|
||||||
|
this.root = newRoot;
|
||||||
|
}
|
||||||
|
return factor == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFixup(y, parent) {
|
||||||
|
let x = (y) ? y : parent;
|
||||||
|
|
||||||
|
let factor = balanceFactor(x);
|
||||||
|
switch (factor) {
|
||||||
|
case 0:
|
||||||
|
updateRank(x);
|
||||||
|
return false;
|
||||||
|
case -1:
|
||||||
|
case 1:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rotatingAroundRoot = x.parent == null;
|
||||||
|
let [z, leaning, toLeft, toRight] = [x.left, -1, rotateRight, rotateLeft];
|
||||||
|
if (factor == 2) {
|
||||||
|
[z, leaning, toLeft, toRight] = [x.right, 1, rotateLeft, rotateRight];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.deleteRotate(x, z, leaning, rotatingAroundRoot, toLeft, toRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRebalance(node, parent) {
|
||||||
|
while (node || parent) {
|
||||||
|
this.deleteFixup(node, parent);
|
||||||
|
[node, parent] = [parent, (parent) ? parent.parent : null];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
172
node.js
Normal file
172
node.js
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
const LEAF = 0;
|
||||||
|
const UNARY = 1;
|
||||||
|
const BINARY = 2;
|
||||||
|
|
||||||
|
function nodeHeight(node) {
|
||||||
|
if (node == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1 + Math.max(nodeHeight(node.left), nodeHeight(node.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeRank(node) {
|
||||||
|
if (node == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return node.rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeDifference(node, parent) {
|
||||||
|
if (parent === undefined) {
|
||||||
|
parent = node != null ? node.parent : null;
|
||||||
|
}
|
||||||
|
return nodeRank(parent) - nodeRank(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeDifferences(node) {
|
||||||
|
let r = nodeRank(node);
|
||||||
|
let left = null;
|
||||||
|
let right = null;
|
||||||
|
|
||||||
|
if (node != null) {
|
||||||
|
left = node.left;
|
||||||
|
right = node.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [r - nodeRank(left), r - nodeRank(right)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateRight(x) {
|
||||||
|
let parent = x.parent;
|
||||||
|
let y = x.left;
|
||||||
|
// let z = x.right;
|
||||||
|
|
||||||
|
if (parent != null) {
|
||||||
|
if (parent.left === x) {
|
||||||
|
parent.left = y;
|
||||||
|
} else {
|
||||||
|
parent.right = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x.left = y.right;
|
||||||
|
if (x.left != null) {
|
||||||
|
x.left.parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
y.right = x;
|
||||||
|
x.parent = y;
|
||||||
|
y.parent = parent;
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateLeft(x) {
|
||||||
|
let parent = x.parent;
|
||||||
|
// let y = x.left;
|
||||||
|
let z = x.right;
|
||||||
|
|
||||||
|
if (parent != null) {
|
||||||
|
if (parent.left === x) {
|
||||||
|
parent.left = z;
|
||||||
|
} else {
|
||||||
|
parent.right = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x.right = z.left;
|
||||||
|
if (x.right != null) {
|
||||||
|
x.right.parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
z.left = x;
|
||||||
|
x.parent = z;
|
||||||
|
z.parent = parent;
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findParentNode(value, node, missing) {
|
||||||
|
if (missing === undefined) {
|
||||||
|
missing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode = node
|
||||||
|
|
||||||
|
while (newNode && (missing || newNode.value != value)) {
|
||||||
|
node = newNode;
|
||||||
|
if (value < node.value) {
|
||||||
|
newNode = node.left;
|
||||||
|
} else if (node.value < value) {
|
||||||
|
newNode = node.right;
|
||||||
|
} else {
|
||||||
|
// same value
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeSearch(value, node) {
|
||||||
|
while (node && node.value != value) {
|
||||||
|
node = (value < node.value) ? node.left : node.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeMinimum(node) {
|
||||||
|
while (node.left != null) {
|
||||||
|
node = node.left;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeMaximum(node) {
|
||||||
|
while (node.right != null) {
|
||||||
|
node = node.right;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
constructor(value, left, right, parent) {
|
||||||
|
this.value = value;
|
||||||
|
this.rank = 0;
|
||||||
|
|
||||||
|
this.parent = parent || null;
|
||||||
|
this.left = left || null;
|
||||||
|
this.right = right || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type() {
|
||||||
|
if (this.left != null && this.right != null) {
|
||||||
|
return BINARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.left != null || this.right != null) {
|
||||||
|
return UNARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LEAF;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize() {
|
||||||
|
return `Node(value=${this.value}, rank = ${this.rank}, left=${this.left}, right=${this.right}, parent=${this.parent})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `Node(value=${this.value}, rank=${this.rank})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
promote() {
|
||||||
|
this.rank++;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
demote() {
|
||||||
|
this.rank--;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
165
ranked_tree.js
Normal file
165
ranked_tree.js
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
class Queue {
|
||||||
|
constructor() {
|
||||||
|
this.q = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueue(x) {
|
||||||
|
this.q.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
dequeue() {
|
||||||
|
return this.q.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return this.q.length == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RankedTree {
|
||||||
|
constructor() {
|
||||||
|
this.root = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getUnwrappedGraph() {
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
let q = new Queue();
|
||||||
|
q.enqueue(this.root);
|
||||||
|
|
||||||
|
let edges = [];
|
||||||
|
while (!q.isEmpty()) {
|
||||||
|
let node = q.dequeue();
|
||||||
|
if (!q) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += `"${node.toString()}" [label="${node.value}, ${node.rank}"];\n`;
|
||||||
|
|
||||||
|
[node.left, node.right].filter(child => child).forEach(child => {
|
||||||
|
edges.push([node, child]);
|
||||||
|
q.enqueue(child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
edges.forEach(vertices => {
|
||||||
|
let [u, v] = vertices;
|
||||||
|
result += `"${u.toString()}" -> "${v.toString()}" [label="${nodeDifference(v)}"]\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `digraph {\n${this._getUnwrappedGraph()}}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
rank() {
|
||||||
|
return nodeRank(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCorrect() {
|
||||||
|
return this.isCorrectNode(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
search(value, node) {
|
||||||
|
return nodeSearch(value, node || this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(value) {
|
||||||
|
let insertedNode = new Node(value);
|
||||||
|
|
||||||
|
if (!this.root) {
|
||||||
|
this.root = insertedNode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent = findParentNode(value, this.root);
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertedNode.parent = parent;
|
||||||
|
|
||||||
|
if (value < parent.value) {
|
||||||
|
parent.left = insertedNode;
|
||||||
|
} else {
|
||||||
|
parent.right = insertedNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.insertRebalance(insertedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
transplant(u, v) {
|
||||||
|
if (!u.parent) {
|
||||||
|
this.root = v;
|
||||||
|
} else if (u.parent.left === u) {
|
||||||
|
u.parent.left = v;
|
||||||
|
} else {
|
||||||
|
u.parent.right = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v) {
|
||||||
|
v.rank = u.rank;
|
||||||
|
v.parent = u.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteNode(node) {
|
||||||
|
if (!node) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [y, parent] = [null, node.parent];
|
||||||
|
|
||||||
|
if (!node.left) {
|
||||||
|
y = node.right;
|
||||||
|
this.transplant(node, node.right);
|
||||||
|
} else if (!node.right) {
|
||||||
|
y = node.left;
|
||||||
|
this.transplant(node, node.left);
|
||||||
|
} else {
|
||||||
|
let successor = nodeMinimum(node.right);
|
||||||
|
parent = (successor.parent != node) ? successor.parent : successor;
|
||||||
|
|
||||||
|
if (successor.parent != node) {
|
||||||
|
parent = (successor.right) ? successor.right : successor.parent;
|
||||||
|
this.transplant(successor, successor.right);
|
||||||
|
successor.right = node.right;
|
||||||
|
successor.right.parent = successor;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transplant(node, successor);
|
||||||
|
successor.left = node.left;
|
||||||
|
node.left.parent = successor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [y, parent];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(value) {
|
||||||
|
let node = this.root;
|
||||||
|
while (node && node.value != value) {
|
||||||
|
node = (value < node.value) ? node.left : node.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
let toRebalance = this.deleteNode(node);
|
||||||
|
if (toRebalance) {
|
||||||
|
let [y, parent] = toRebalance;
|
||||||
|
this.deleteRebalance(y, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* abstract methods */
|
||||||
|
isCorrectNode(node) {
|
||||||
|
throw "not implemented!";
|
||||||
|
}
|
||||||
|
|
||||||
|
insertRebalance(node) {
|
||||||
|
throw "not implemented!";
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRebalance(node, parent) {
|
||||||
|
throw "not implemented!";
|
||||||
|
}
|
||||||
|
}
|
18
ravl.js
Normal file
18
ravl.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
class RAVLTree extends WAVLTree {
|
||||||
|
isCorrectNode(node, recursive) {
|
||||||
|
if (!node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodeDifferences(node).filter(d => d <= 0).length > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !recursive || (this.isCorrectNode(node.left) && this.isCorrectNode(node.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRebalance(node, parent) {
|
||||||
|
// no-op
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
123
wavl.js
Normal file
123
wavl.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
class WAVLTree extends AVLTree {
|
||||||
|
isCorrectNode(node, recursive) {
|
||||||
|
if (!node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeDifferences(node).forEach(childRank => {
|
||||||
|
if ([1, 2].findIndex(childRank) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (node.type() == LEAF) {
|
||||||
|
return node.rank == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(recursive ?? true) || (this.isCorrectNode(node.left) && this.isCorrectNode(node.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
fixDelete(x, y, z, reversed, rotateLeft, rotateRight) {
|
||||||
|
let newRoot = x;
|
||||||
|
let [v, w] = [y.left, y.right];
|
||||||
|
|
||||||
|
if (reversed) {
|
||||||
|
[v, w] = [w, v];
|
||||||
|
}
|
||||||
|
|
||||||
|
let wDiff = nodeDifference(w, y);
|
||||||
|
|
||||||
|
if (wDiff == 1 && y.parent) {
|
||||||
|
newRoot = rotateLeft(y.parent);
|
||||||
|
|
||||||
|
y.promote();
|
||||||
|
z.demote();
|
||||||
|
|
||||||
|
if (z.type() == LEAF) {
|
||||||
|
z.demote();
|
||||||
|
}
|
||||||
|
} else if (wDiff == 2 && v && v.parent) {
|
||||||
|
rotateRight(v.parent);
|
||||||
|
newRoot = rotateLeft(v.parent);
|
||||||
|
|
||||||
|
v.promote().promote();
|
||||||
|
y.demote();
|
||||||
|
z.demote().demote();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomUpDelete(x, parent) {
|
||||||
|
let xDiff = nodeDifference(x, parent);
|
||||||
|
if (xDiff != 3 || !parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = (parent.left === x) ? parent.right : parent.left;
|
||||||
|
let yDiff = nodeDifference(y, parent);
|
||||||
|
|
||||||
|
while (parent && xDiff == 3 && y && (yDiff == 2 || nodeDifferences(y).equals([2, 2]))) {
|
||||||
|
parent.demote();
|
||||||
|
if (yDiff != 2) {
|
||||||
|
y.demote();
|
||||||
|
}
|
||||||
|
|
||||||
|
x = parent;
|
||||||
|
parent = x.parent;
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = (parent.left === x) ? parent.right : parent.left;
|
||||||
|
|
||||||
|
xDiff = nodeDifference(x, parent);
|
||||||
|
yDiff = nodeDifference(y, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rotatingAroundRoot = parent.parent == null;
|
||||||
|
let newRoot = parent;
|
||||||
|
|
||||||
|
let parentNodeDiffs = nodeDifferences(parent);
|
||||||
|
if (parentNodeDiffs.sort().equals([1, 3])) {
|
||||||
|
if (parent.left === x) {
|
||||||
|
newRoot = this.fixDelete(x, parent.right, parent, false, rotateLeft, rotateRight);
|
||||||
|
} else {
|
||||||
|
newRoot = this.fixDelete(x, parent.left, parent, true, rotateRight, rotateLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotatingAroundRoot) {
|
||||||
|
this.root = newRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFixup(y, parent) {
|
||||||
|
let z = (y) ? y : parent;
|
||||||
|
|
||||||
|
if (nodeDifferences(z).equals([2, 2])) {
|
||||||
|
z.demote();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[parent.left, parent.right].forEach(y => {
|
||||||
|
if (nodeDifference(y, parent) == 3) {
|
||||||
|
this.bottomUpDelete(y, parent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRebalance(node, parent) {
|
||||||
|
while (node || parent) {
|
||||||
|
this.deleteFixup(node, parent);
|
||||||
|
[node, parent] = parent, (parent) ? parent.parent : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue