feat: Add comments to currently run operations

Fixes #8

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-05-15 17:53:12 +02:00
parent 23a0653d23
commit c7c27300f6
Signed by: mfocko
GPG key ID: 7C47D46246790496
7 changed files with 79 additions and 39 deletions

30
avl.js
View file

@ -41,28 +41,32 @@ class AVLTree extends RankedTree {
if (rotatingAroundRoot) { if (rotatingAroundRoot) {
this.root = newRoot; this.root = newRoot;
} }
this.record(); this.record("Fixing 0-child by single rotation: by z");
z.demote(); z.demote();
this.record(); this.record("Fixing 0-child by single rotation: demoting z");
} else if (nodeDifference(y) == 1) { } else if (nodeDifference(y) == 1) {
rotateLeft(x); rotateLeft(x);
this.record(); this.record(
"Fixing 0-child by double-rotation: first rotation by x"
);
newRoot = rotateRight(z); newRoot = rotateRight(z);
if (rotatingAroundRoot) { if (rotatingAroundRoot) {
this.root = newRoot; this.root = newRoot;
} }
this.record(); this.record(
"Fixing 0-child by double-rotation: second rotation by z"
);
y.promote(); y.promote();
this.record(); this.record("Fixing 0-child by double-rotation: promoting y");
x.demote(); x.demote();
this.record(); this.record("Fixing 0-child by double-rotation: demoting x");
z.demote(); z.demote();
this.record(); this.record("Fixing 0-child by double-rotation: demoting z");
} }
} }
@ -72,7 +76,7 @@ class AVLTree extends RankedTree {
x.parent.promote(); x.parent.promote();
x = x.parent; x = x.parent;
this.record(); this.record("Insertion rebalance: promoting (0, 1) parent");
diffs = nodeDifferences(x.parent).sort(); diffs = nodeDifferences(x.parent).sort();
} }
@ -122,7 +126,7 @@ class AVLTree extends RankedTree {
break; break;
default: default:
rotateRight(y); rotateRight(y);
this.record(); this.record("AVL deletion, fixing by double-rotation: by y");
newRoot = rotateLeft(x); newRoot = rotateLeft(x);
break; break;
@ -130,13 +134,13 @@ class AVLTree extends RankedTree {
if (rotatingAroundRoot) { if (rotatingAroundRoot) {
this.root = newRoot; this.root = newRoot;
} }
this.record(); this.record("AVL deletion, fixing by rotation by x");
[newRoot.left, newRoot.right, newRoot] [newRoot.left, newRoot.right, newRoot]
.filter((x) => x) .filter((x) => x)
.forEach((n) => { .forEach((n) => {
updateRank(n); updateRank(n);
this.record(); this.record("Updating rank of nodes affected by rotations");
}); });
return factor == 0; return factor == 0;
@ -149,7 +153,9 @@ class AVLTree extends RankedTree {
switch (factor) { switch (factor) {
case 0: case 0:
updateRank(x); updateRank(x);
this.record(); this.record(
"Updating rank of node affected by the propagation of delete"
);
return false; return false;
case -1: case -1:

View file

@ -1,9 +1,11 @@
let lRecorder = new Recorder( let lRecorder = new Recorder(
d3.select("#left").graphviz(), d3.select("#left").graphviz(),
null,
"left" "left"
).renderAtOnce(); ).renderAtOnce();
let rRecorder = new Recorder( let rRecorder = new Recorder(
d3.select("#right").graphviz(), d3.select("#right").graphviz(),
null,
"right" "right"
).renderAtOnce(); ).renderAtOnce();

View file

@ -32,6 +32,7 @@
<input type="submit" value="Delete" /> <input type="submit" value="Delete" />
</form> </form>
<p>Current operation: <span id="comment"></span></p>
<div id="graph" style="text-align: center"></div> <div id="graph" style="text-align: center"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

View file

@ -68,11 +68,11 @@ class RankedTree {
return this.toDot().join("\n"); return this.toDot().join("\n");
} }
record() { record(message) {
if (!this.recorder) { if (!this.recorder) {
return; return;
} }
this.recorder.record(this); this.recorder.record(this, message);
} }
rank() { rank() {
@ -92,7 +92,7 @@ class RankedTree {
if (!this.root) { if (!this.root) {
this.root = insertedNode; this.root = insertedNode;
this.record(); this.record("Inserting key to the root");
return; return;
} }
@ -108,7 +108,7 @@ class RankedTree {
} else { } else {
parent.right = insertedNode; parent.right = insertedNode;
} }
this.record(); this.record("Inserting key");
this.insertRebalance(insertedNode); this.insertRebalance(insertedNode);
} }
@ -146,12 +146,14 @@ class RankedTree {
node.value = successor.value; node.value = successor.value;
successor.value = null; successor.value = null;
this.record(); this.record(
"Replacing the value of deleted node with successor value"
);
return this.deleteNode(successor); return this.deleteNode(successor);
} }
this.record(); this.record("Replacing the node with one of its children");
return [y, parent]; return [y, parent];
} }

View file

@ -1,8 +1,23 @@
const DURATION = 500; const DURATION = 500;
class Record {
constructor(tree, message) {
this.tree = tree;
this.message = message;
}
render(graph, textBox) {
graph.renderDot(this.tree);
if (textBox) {
textBox.textContent = this.message;
}
}
}
class Recorder { class Recorder {
constructor(graph, id) { constructor(graph, textBox, id) {
this.graph = graph; this.graph = graph;
this.textBox = textBox;
this.id = id; this.id = id;
this.rendered = -1; this.rendered = -1;
@ -20,8 +35,6 @@ class Recorder {
} }
unblockRendering() { unblockRendering() {
console.log(this);
console.log(`Unblocked renderer #${this.id}`);
this.rendering = false; this.rendering = false;
} }
@ -40,7 +53,7 @@ class Recorder {
if (this.atOnce) { if (this.atOnce) {
if (this.rendered != this.states.length - 1) { if (this.rendered != this.states.length - 1) {
this.rendered = this.states.length - 1; this.rendered = this.states.length - 1;
this.graph.renderDot(this.states[this.rendered]); this.states[this.rendered].render(this.graph, this.textBox);
} }
return; return;
@ -57,7 +70,7 @@ class Recorder {
this.rendering = true; this.rendering = true;
this.rendered++; this.rendered++;
this.graph.renderDot(this.states[this.rendered]); this.states[this.rendered].render(this.graph, this.textBox);
} }
previous() { previous() {
@ -68,9 +81,9 @@ class Recorder {
throw "not implemented!"; throw "not implemented!";
} }
record(tree) { record(tree, message) {
// TODO: adjust join if necessary // TODO: adjust join if necessary
this.states.push(tree.toDot().join("")); this.states.push(new Record(tree.toDot().join(""), message));
this.render(); this.render();
} }
} }

View file

@ -1,4 +1,8 @@
let recorder = new Recorder(d3.select("#graph").graphviz(), "graph"); let recorder = new Recorder(
d3.select("#graph").graphviz(),
document.getElementById("comment"),
"graph"
);
let tree = new WAVLTree(); let tree = new WAVLTree();
tree.recorder = recorder; tree.recorder = recorder;

38
wavl.js
View file

@ -36,36 +36,48 @@ class WAVLTree extends AVLTree {
if (rotatingAroundRoot) { if (rotatingAroundRoot) {
this.root = newRoot; this.root = newRoot;
} }
this.record(); this.record(
"Final step of deletion rebalance: single rotation by parent of y"
);
y.promote(); y.promote();
this.record(); this.record("Final step of deletion rebalance: promotion of y");
z.demote(); z.demote();
this.record(); this.record("Final step of deletion rebalance: demotion of z");
if (z.type() == LEAF) { if (z.type() == LEAF) {
z.demote(); z.demote();
this.record(); this.record(
"Final step of deletion rebalance: demotion of leaf z"
);
} }
} else if (wDiff == 2 && v && v.parent) { } else if (wDiff == 2 && v && v.parent) {
rotateRight(v.parent); rotateRight(v.parent);
this.record(); this.record(
"Final step of deletion rebalance: first of double rotation by parent of v"
);
newRoot = rotateLeft(v.parent); newRoot = rotateLeft(v.parent);
if (rotatingAroundRoot) { if (rotatingAroundRoot) {
this.root = newRoot; this.root = newRoot;
} }
this.record(); this.record(
"Final step of deletion rebalance: second of double rotation by parent of v"
);
v.promote().promote(); v.promote().promote();
this.record(); this.record(
"Final step of deletion rebalance: double promotion of v"
);
y.demote(); y.demote();
this.record(); this.record("Final step of deletion rebalance: demotion of y");
z.demote().demote(); z.demote().demote();
this.record(); this.record(
"Final step of deletion rebalance: double demotion of z"
);
} }
} }
@ -85,11 +97,11 @@ class WAVLTree extends AVLTree {
(yDiff == 2 || nodeDifferences(y).equals([2, 2])) (yDiff == 2 || nodeDifferences(y).equals([2, 2]))
) { ) {
parent.demote(); parent.demote();
this.record(); this.record("Propagating error by demoting parent");
if (yDiff != 2) { if (yDiff != 2) {
y.demote(); y.demote();
this.record(); this.record("Demoting y");
} }
x = parent; x = parent;
@ -139,12 +151,12 @@ class WAVLTree extends AVLTree {
deleteFixup(y, parent) { deleteFixup(y, parent) {
if (nodeDifferences(y).equals([2, 2])) { if (nodeDifferences(y).equals([2, 2])) {
y.demote(); y.demote();
this.record(); this.record("Starting deletion rebalance by demoting (2, 2) node");
parent = y.parent; parent = y.parent;
} else if (nodeDifferences(parent).equals([2, 2])) { } else if (nodeDifferences(parent).equals([2, 2])) {
parent.demote(); parent.demote();
this.record(); this.record("Starting deletion rebalance by demoting (2, 2) node");
parent = parent.parent; parent = parent.parent;
} }