2022-04-27 21:37:58 +02:00
|
|
|
class WAVLTree extends AVLTree {
|
|
|
|
isCorrectNode(node, recursive) {
|
|
|
|
if (!node) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-01 17:09:46 +02:00
|
|
|
nodeDifferences(node).forEach((childRank) => {
|
2022-05-06 09:43:32 +02:00
|
|
|
if ([1, 2].indexOf(childRank) == -1) {
|
2022-04-27 21:37:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (node.type() == LEAF) {
|
|
|
|
return node.rank == 0;
|
|
|
|
}
|
|
|
|
|
2022-05-07 17:11:07 +02:00
|
|
|
recursive = recursive ?? true;
|
2022-05-01 17:09:46 +02:00
|
|
|
return (
|
2022-05-07 17:11:07 +02:00
|
|
|
!recursive ||
|
2022-05-01 17:09:46 +02:00
|
|
|
(this.isCorrectNode(node.left) && this.isCorrectNode(node.right))
|
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
|
2022-05-06 09:46:03 +02:00
|
|
|
fixDelete(x, y, z, reversed, rotatingAroundRoot, rotateLeft, rotateRight) {
|
2022-04-27 21:37:58 +02:00
|
|
|
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);
|
2022-05-06 09:46:03 +02:00
|
|
|
if (rotatingAroundRoot) {
|
|
|
|
this.root = newRoot;
|
|
|
|
}
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: single rotation by parent of y",
|
|
|
|
y.parent
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
|
|
|
|
y.promote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record("Final step of deletion rebalance: promotion of y", y);
|
2022-05-06 09:46:03 +02:00
|
|
|
|
2022-04-27 21:37:58 +02:00
|
|
|
z.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record("Final step of deletion rebalance: demotion of z", z);
|
2022-04-27 21:37:58 +02:00
|
|
|
|
|
|
|
if (z.type() == LEAF) {
|
|
|
|
z.demote();
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: demotion of leaf z",
|
|
|
|
z
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
} else if (wDiff == 2 && v && v.parent) {
|
|
|
|
rotateRight(v.parent);
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: first of double rotation by parent of v",
|
|
|
|
v.parent
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-05-06 09:46:03 +02:00
|
|
|
|
2022-04-27 21:37:58 +02:00
|
|
|
newRoot = rotateLeft(v.parent);
|
2022-05-06 09:46:03 +02:00
|
|
|
if (rotatingAroundRoot) {
|
|
|
|
this.root = newRoot;
|
|
|
|
}
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: second of double rotation by parent of v",
|
|
|
|
v.parent
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
|
|
|
|
v.promote().promote();
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: double promotion of v",
|
|
|
|
v
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-05-06 09:46:03 +02:00
|
|
|
|
2022-04-27 21:37:58 +02:00
|
|
|
y.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record("Final step of deletion rebalance: demotion of y", y);
|
2022-05-06 09:46:03 +02:00
|
|
|
|
2022-04-27 21:37:58 +02:00
|
|
|
z.demote().demote();
|
2022-05-15 17:53:12 +02:00
|
|
|
this.record(
|
2022-05-15 22:28:42 +02:00
|
|
|
"Final step of deletion rebalance: double demotion of z",
|
|
|
|
z
|
2022-05-15 17:53:12 +02:00
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bottomUpDelete(x, parent) {
|
|
|
|
let xDiff = nodeDifference(x, parent);
|
|
|
|
if (xDiff != 3 || !parent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-01 17:09:46 +02:00
|
|
|
let y = parent.left === x ? parent.right : parent.left;
|
2022-04-27 21:37:58 +02:00
|
|
|
let yDiff = nodeDifference(y, parent);
|
|
|
|
|
2022-05-01 17:09:46 +02:00
|
|
|
while (
|
|
|
|
parent &&
|
|
|
|
xDiff == 3 &&
|
|
|
|
y &&
|
|
|
|
(yDiff == 2 || nodeDifferences(y).equals([2, 2]))
|
|
|
|
) {
|
2022-04-27 21:37:58 +02:00
|
|
|
parent.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record("Propagating error by demoting parent", parent);
|
2022-05-06 09:46:03 +02:00
|
|
|
|
2022-04-27 21:37:58 +02:00
|
|
|
if (yDiff != 2) {
|
|
|
|
y.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record("Demoting y", y);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
x = parent;
|
|
|
|
parent = x.parent;
|
|
|
|
if (!parent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-07 16:53:50 +02:00
|
|
|
y = parent.left === x ? parent.right : parent.left;
|
2022-04-27 21:37:58 +02:00
|
|
|
|
|
|
|
xDiff = nodeDifference(x, parent);
|
|
|
|
yDiff = nodeDifference(y, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let rotatingAroundRoot = parent.parent == null;
|
|
|
|
|
|
|
|
let parentNodeDiffs = nodeDifferences(parent);
|
|
|
|
if (parentNodeDiffs.sort().equals([1, 3])) {
|
|
|
|
if (parent.left === x) {
|
2022-05-06 09:46:03 +02:00
|
|
|
this.fixDelete(
|
2022-05-01 17:09:46 +02:00
|
|
|
x,
|
|
|
|
parent.right,
|
|
|
|
parent,
|
|
|
|
false,
|
2022-05-06 09:46:03 +02:00
|
|
|
rotatingAroundRoot,
|
2022-05-01 17:09:46 +02:00
|
|
|
rotateLeft,
|
|
|
|
rotateRight
|
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
} else {
|
2022-05-06 09:46:03 +02:00
|
|
|
this.fixDelete(
|
2022-05-01 17:09:46 +02:00
|
|
|
x,
|
|
|
|
parent.left,
|
|
|
|
parent,
|
|
|
|
true,
|
2022-05-06 09:46:03 +02:00
|
|
|
rotatingAroundRoot,
|
2022-05-01 17:09:46 +02:00
|
|
|
rotateRight,
|
|
|
|
rotateLeft
|
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteFixup(y, parent) {
|
2022-05-07 16:53:50 +02:00
|
|
|
if (nodeDifferences(y).equals([2, 2])) {
|
|
|
|
y.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record(
|
|
|
|
"Starting deletion rebalance by demoting (2, 2) node",
|
|
|
|
y
|
|
|
|
);
|
2022-04-27 21:37:58 +02:00
|
|
|
|
2022-05-07 16:53:50 +02:00
|
|
|
parent = y.parent;
|
|
|
|
} else if (nodeDifferences(parent).equals([2, 2])) {
|
|
|
|
parent.demote();
|
2022-05-15 22:28:42 +02:00
|
|
|
this.record(
|
|
|
|
"Starting deletion rebalance by demoting (2, 2) node",
|
|
|
|
parent
|
|
|
|
);
|
2022-05-07 16:53:50 +02:00
|
|
|
|
|
|
|
parent = parent.parent;
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-01 17:09:46 +02:00
|
|
|
[parent.left, parent.right].forEach((y) => {
|
2022-04-27 21:37:58 +02:00
|
|
|
if (nodeDifference(y, parent) == 3) {
|
|
|
|
this.bottomUpDelete(y, parent);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteRebalance(node, parent) {
|
2022-05-06 09:47:03 +02:00
|
|
|
this.deleteFixup(node, parent);
|
2022-04-27 21:37:58 +02:00
|
|
|
}
|
2022-05-01 17:09:46 +02:00
|
|
|
}
|