feat: highlight currently affected node
Fixes #7 Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
30b00e5d1a
commit
01f00eb330
4 changed files with 64 additions and 40 deletions
33
avl.js
33
avl.js
|
@ -41,14 +41,15 @@ class AVLTree extends RankedTree {
|
|||
if (rotatingAroundRoot) {
|
||||
this.root = newRoot;
|
||||
}
|
||||
this.record("Fixing 0-child by single rotation: by z");
|
||||
this.record("Fixing 0-child by single rotation: by z", z);
|
||||
|
||||
z.demote();
|
||||
this.record("Fixing 0-child by single rotation: demoting z");
|
||||
this.record("Fixing 0-child by single rotation: demoting z", z);
|
||||
} else if (nodeDifference(y) == 1) {
|
||||
rotateLeft(x);
|
||||
this.record(
|
||||
"Fixing 0-child by double-rotation: first rotation by x"
|
||||
"Fixing 0-child by double-rotation: first rotation by x",
|
||||
x
|
||||
);
|
||||
|
||||
newRoot = rotateRight(z);
|
||||
|
@ -56,17 +57,18 @@ class AVLTree extends RankedTree {
|
|||
this.root = newRoot;
|
||||
}
|
||||
this.record(
|
||||
"Fixing 0-child by double-rotation: second rotation by z"
|
||||
"Fixing 0-child by double-rotation: second rotation by z",
|
||||
z
|
||||
);
|
||||
|
||||
y.promote();
|
||||
this.record("Fixing 0-child by double-rotation: promoting y");
|
||||
this.record("Fixing 0-child by double-rotation: promoting y", y);
|
||||
|
||||
x.demote();
|
||||
this.record("Fixing 0-child by double-rotation: demoting x");
|
||||
this.record("Fixing 0-child by double-rotation: demoting x", x);
|
||||
|
||||
z.demote();
|
||||
this.record("Fixing 0-child by double-rotation: demoting z");
|
||||
this.record("Fixing 0-child by double-rotation: demoting z", z);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,10 +76,12 @@ class AVLTree extends RankedTree {
|
|||
let diffs = nodeDifferences(x.parent).sort();
|
||||
while (x.parent && diffs.equals([0, 1])) {
|
||||
x.parent.promote();
|
||||
this.record(
|
||||
"Insertion rebalance: promoting (0, 1) parent",
|
||||
x.parent
|
||||
);
|
||||
|
||||
x = x.parent;
|
||||
|
||||
this.record("Insertion rebalance: promoting (0, 1) parent");
|
||||
|
||||
diffs = nodeDifferences(x.parent).sort();
|
||||
}
|
||||
|
||||
|
@ -126,7 +130,7 @@ class AVLTree extends RankedTree {
|
|||
break;
|
||||
default:
|
||||
rotateRight(y);
|
||||
this.record("AVL deletion, fixing by double-rotation: by y");
|
||||
this.record("AVL deletion, fixing by double-rotation: by y", y);
|
||||
|
||||
newRoot = rotateLeft(x);
|
||||
break;
|
||||
|
@ -134,13 +138,13 @@ class AVLTree extends RankedTree {
|
|||
if (rotatingAroundRoot) {
|
||||
this.root = newRoot;
|
||||
}
|
||||
this.record("AVL deletion, fixing by rotation by x");
|
||||
this.record("AVL deletion, fixing by rotation by x", x);
|
||||
|
||||
[newRoot.left, newRoot.right, newRoot]
|
||||
.filter((x) => x)
|
||||
.forEach((n) => {
|
||||
updateRank(n);
|
||||
this.record("Updating rank of nodes affected by rotations");
|
||||
this.record("Updating rank of nodes affected by rotations", n);
|
||||
});
|
||||
|
||||
return factor == 0;
|
||||
|
@ -154,7 +158,8 @@ class AVLTree extends RankedTree {
|
|||
case 0:
|
||||
updateRank(x);
|
||||
this.record(
|
||||
"Updating rank of node affected by the propagation of delete"
|
||||
"Updating rank of node affected by the propagation of delete",
|
||||
x
|
||||
);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -22,7 +22,7 @@ class RankedTree {
|
|||
this.recorder = null;
|
||||
}
|
||||
|
||||
_getUnwrappedGraph() {
|
||||
_getUnwrappedGraph(highlightedNode) {
|
||||
let result = [];
|
||||
|
||||
let q = new Queue();
|
||||
|
@ -36,7 +36,11 @@ class RankedTree {
|
|||
}
|
||||
|
||||
let [value, rank] = [node.value, node.rank];
|
||||
result.push(`\t"Node(${value})" [label="${value}, ${rank}"];`);
|
||||
let highlight =
|
||||
node === highlightedNode ? ', color="blue", penwidth=3' : "";
|
||||
result.push(
|
||||
`\t"Node(${value})" [label="${value}, ${rank}"${highlight}];`
|
||||
);
|
||||
|
||||
[node.left, node.right]
|
||||
.filter((child) => child)
|
||||
|
@ -60,19 +64,19 @@ class RankedTree {
|
|||
return result;
|
||||
}
|
||||
|
||||
toDot() {
|
||||
return ["digraph {", ...this._getUnwrappedGraph(), "}"];
|
||||
toDot(highlightedNode) {
|
||||
return ["digraph {", ...this._getUnwrappedGraph(highlightedNode), "}"];
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.toDot().join("\n");
|
||||
}
|
||||
|
||||
record(message) {
|
||||
record(message, highlightedNode) {
|
||||
if (!this.recorder) {
|
||||
return;
|
||||
}
|
||||
this.recorder.record(this, message);
|
||||
this.recorder.record(this, message, highlightedNode);
|
||||
}
|
||||
|
||||
rank() {
|
||||
|
@ -92,7 +96,7 @@ class RankedTree {
|
|||
|
||||
if (!this.root) {
|
||||
this.root = insertedNode;
|
||||
this.record("Inserting key to the root");
|
||||
this.record("Inserting key to the root", insertedNode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -108,7 +112,7 @@ class RankedTree {
|
|||
} else {
|
||||
parent.right = insertedNode;
|
||||
}
|
||||
this.record("Inserting key");
|
||||
this.record("Inserting key", insertedNode);
|
||||
|
||||
this.insertRebalance(insertedNode);
|
||||
}
|
||||
|
@ -147,13 +151,14 @@ class RankedTree {
|
|||
node.value = successor.value;
|
||||
successor.value = null;
|
||||
this.record(
|
||||
"Replacing the value of deleted node with successor value"
|
||||
"Replacing the value of deleted node with successor value",
|
||||
node
|
||||
);
|
||||
|
||||
return this.deleteNode(successor);
|
||||
}
|
||||
|
||||
this.record("Replacing the node with one of its children");
|
||||
this.record("Replacing the node with one of its children", node);
|
||||
|
||||
return [y, parent];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const DURATION = 500;
|
||||
const DURATION = 750;
|
||||
|
||||
class Record {
|
||||
constructor(tree, message) {
|
||||
|
@ -81,9 +81,11 @@ class Recorder {
|
|||
throw "not implemented!";
|
||||
}
|
||||
|
||||
record(tree, message) {
|
||||
record(tree, message, highlightedNode) {
|
||||
// TODO: adjust join if necessary
|
||||
this.states.push(new Record(tree.toDot().join(""), message));
|
||||
this.states.push(
|
||||
new Record(tree.toDot(highlightedNode).join(""), message)
|
||||
);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
38
wavl.js
38
wavl.js
|
@ -37,25 +37,28 @@ class WAVLTree extends AVLTree {
|
|||
this.root = newRoot;
|
||||
}
|
||||
this.record(
|
||||
"Final step of deletion rebalance: single rotation by parent of y"
|
||||
"Final step of deletion rebalance: single rotation by parent of y",
|
||||
y.parent
|
||||
);
|
||||
|
||||
y.promote();
|
||||
this.record("Final step of deletion rebalance: promotion of y");
|
||||
this.record("Final step of deletion rebalance: promotion of y", y);
|
||||
|
||||
z.demote();
|
||||
this.record("Final step of deletion rebalance: demotion of z");
|
||||
this.record("Final step of deletion rebalance: demotion of z", z);
|
||||
|
||||
if (z.type() == LEAF) {
|
||||
z.demote();
|
||||
this.record(
|
||||
"Final step of deletion rebalance: demotion of leaf z"
|
||||
"Final step of deletion rebalance: demotion of leaf z",
|
||||
z
|
||||
);
|
||||
}
|
||||
} else if (wDiff == 2 && v && v.parent) {
|
||||
rotateRight(v.parent);
|
||||
this.record(
|
||||
"Final step of deletion rebalance: first of double rotation by parent of v"
|
||||
"Final step of deletion rebalance: first of double rotation by parent of v",
|
||||
v.parent
|
||||
);
|
||||
|
||||
newRoot = rotateLeft(v.parent);
|
||||
|
@ -63,20 +66,23 @@ class WAVLTree extends AVLTree {
|
|||
this.root = newRoot;
|
||||
}
|
||||
this.record(
|
||||
"Final step of deletion rebalance: second of double rotation by parent of v"
|
||||
"Final step of deletion rebalance: second of double rotation by parent of v",
|
||||
v.parent
|
||||
);
|
||||
|
||||
v.promote().promote();
|
||||
this.record(
|
||||
"Final step of deletion rebalance: double promotion of v"
|
||||
"Final step of deletion rebalance: double promotion of v",
|
||||
v
|
||||
);
|
||||
|
||||
y.demote();
|
||||
this.record("Final step of deletion rebalance: demotion of y");
|
||||
this.record("Final step of deletion rebalance: demotion of y", y);
|
||||
|
||||
z.demote().demote();
|
||||
this.record(
|
||||
"Final step of deletion rebalance: double demotion of z"
|
||||
"Final step of deletion rebalance: double demotion of z",
|
||||
z
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -97,11 +103,11 @@ class WAVLTree extends AVLTree {
|
|||
(yDiff == 2 || nodeDifferences(y).equals([2, 2]))
|
||||
) {
|
||||
parent.demote();
|
||||
this.record("Propagating error by demoting parent");
|
||||
this.record("Propagating error by demoting parent", parent);
|
||||
|
||||
if (yDiff != 2) {
|
||||
y.demote();
|
||||
this.record("Demoting y");
|
||||
this.record("Demoting y", y);
|
||||
}
|
||||
|
||||
x = parent;
|
||||
|
@ -151,12 +157,18 @@ class WAVLTree extends AVLTree {
|
|||
deleteFixup(y, parent) {
|
||||
if (nodeDifferences(y).equals([2, 2])) {
|
||||
y.demote();
|
||||
this.record("Starting deletion rebalance by demoting (2, 2) node");
|
||||
this.record(
|
||||
"Starting deletion rebalance by demoting (2, 2) node",
|
||||
y
|
||||
);
|
||||
|
||||
parent = y.parent;
|
||||
} else if (nodeDifferences(parent).equals([2, 2])) {
|
||||
parent.demote();
|
||||
this.record("Starting deletion rebalance by demoting (2, 2) node");
|
||||
this.record(
|
||||
"Starting deletion rebalance by demoting (2, 2) node",
|
||||
parent
|
||||
);
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue