fix(rotations): use built-in root adjustment

• remove unnecessary parameters to helper functions
• use built-in root adjustment of the rotate functions
• swap parameters of the rotation functions, to pass the tree first

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-05-22 20:27:02 +02:00
parent 2bc43652d0
commit 5388f21f04
Signed by: mfocko
GPG key ID: 7C47D46246790496
4 changed files with 22 additions and 66 deletions

55
avl.js
View file

@ -33,30 +33,24 @@ class AVLTree extends RankedTree {
); );
} }
fix0Child(x, y, z, rotatingAroundRoot, rotateLeft, rotateRight) { fix0Child(x, y, z, rotateLeft, rotateRight) {
let newRoot = x.parent; let newRoot = x.parent;
if (!y || nodeDifference(y) == 2) { if (!y || nodeDifference(y) == 2) {
newRoot = rotateRight(z); newRoot = rotateRight(this, z);
if (rotatingAroundRoot) {
this.root = newRoot;
}
this.record("Fixing 0-child by single rotation: by z", z, newRoot); this.record("Fixing 0-child by single rotation: by z", z, newRoot);
z.demote(); z.demote();
this.record("Fixing 0-child by single rotation: demoting z", z); this.record("Fixing 0-child by single rotation: demoting z", z);
} else if (nodeDifference(y) == 1) { } else if (nodeDifference(y) == 1) {
let intermediateRoot = rotateLeft(x); let intermediateRoot = rotateLeft(this, x);
this.record( this.record(
"Fixing 0-child by double-rotation: first rotation by x", "Fixing 0-child by double-rotation: first rotation by x",
x, x,
intermediateRoot intermediateRoot
); );
newRoot = rotateRight(z); newRoot = rotateRight(this, z);
if (rotatingAroundRoot) {
this.root = newRoot;
}
this.record( this.record(
"Fixing 0-child by double-rotation: second rotation by z", "Fixing 0-child by double-rotation: second rotation by z",
z, z,
@ -91,8 +85,6 @@ class AVLTree extends RankedTree {
return; return;
} }
let rotatingAroundRoot = x.parent.parent == null;
let rankDifference = nodeDifference(x); let rankDifference = nodeDifference(x);
if (rankDifference != 0) { if (rankDifference != 0) {
return; return;
@ -101,49 +93,32 @@ class AVLTree extends RankedTree {
let xParent = x.parent; let xParent = x.parent;
if (rankDifference == 0 && x.parent.left === x) { if (rankDifference == 0 && x.parent.left === x) {
this.fix0Child( this.fix0Child(x, x.right, xParent, rotateLeft, rotateRight);
x,
x.right,
xParent,
rotatingAroundRoot,
rotateLeft,
rotateRight
);
} else if (rankDifference == 0 && x.parent.right === x) { } else if (rankDifference == 0 && x.parent.right === x) {
this.fix0Child( this.fix0Child(x, x.left, xParent, rotateRight, rotateLeft);
x,
x.left,
xParent,
rotatingAroundRoot,
rotateRight,
rotateLeft
);
} }
} }
deleteRotate(x, y, leaning, rotatingAroundRoot, rotateLeft, rotateRight) { deleteRotate(x, y, leaning, rotateLeft, rotateRight) {
let newRoot = x; let newRoot = x;
let factor = balanceFactor(y); let factor = balanceFactor(y);
switch (factor) { switch (factor) {
case 0: case 0:
case leaning: case leaning:
newRoot = rotateLeft(x); newRoot = rotateLeft(this, x);
break; break;
default: default:
let intermediateRoot = rotateRight(y); let intermediateRoot = rotateRight(this, y);
this.record( this.record(
"AVL deletion, fixing by double-rotation: by y", "AVL deletion, fixing by double-rotation: by y",
y, y,
intermediateRoot intermediateRoot
); );
newRoot = rotateLeft(x); newRoot = rotateLeft(this, x);
break; break;
} }
if (rotatingAroundRoot) {
this.root = newRoot;
}
this.record("AVL deletion, fixing by rotation by x", x, newRoot); this.record("AVL deletion, fixing by rotation by x", x, newRoot);
[newRoot.left, newRoot.right, newRoot] [newRoot.left, newRoot.right, newRoot]
@ -172,7 +147,6 @@ class AVLTree extends RankedTree {
return false; return false;
} }
let rotatingAroundRoot = x.parent == null;
let [z, leaning, toLeft, toRight] = [ let [z, leaning, toLeft, toRight] = [
x.left, x.left,
-1, -1,
@ -188,14 +162,7 @@ class AVLTree extends RankedTree {
]; ];
} }
return this.deleteRotate( return this.deleteRotate(x, z, leaning, toLeft, toRight);
x,
z,
leaning,
rotatingAroundRoot,
toLeft,
toRight
);
} }
deleteRebalance(node, parent) { deleteRebalance(node, parent) {

View file

@ -36,7 +36,7 @@ function nodeDifferences(node) {
return [r - nodeRank(left), r - nodeRank(right)]; return [r - nodeRank(left), r - nodeRank(right)];
} }
function rotateRight(x, t) { function rotateRight(t, x) {
let parent = x.parent; let parent = x.parent;
let y = x.left; let y = x.left;
// let z = x.right; // let z = x.right;
@ -63,7 +63,7 @@ function rotateRight(x, t) {
return y; return y;
} }
function rotateLeft(x, t) { function rotateLeft(t, x) {
let parent = x.parent; let parent = x.parent;
// let y = x.left; // let y = x.left;
let z = x.right; let z = x.right;

10
rbt.js
View file

@ -47,13 +47,13 @@ class RBTree extends RankedTree {
// ====== // ======
// zs uncle y is black and z is a right child // zs uncle y is black and z is a right child
z = p; z = p;
rotateLeft(p, this); rotateLeft(this, p);
this.record("Insertion case #2: rotating by parent"); this.record("Insertion case #2: rotating by parent");
} else { } else {
// Case 3 // Case 3
// ====== // ======
// zs uncle y is black and z is a left child // zs uncle y is black and z is a left child
rotateRight(pp, this); rotateRight(this, pp);
this.record("Insertion case #3: rotating by grandparent"); this.record("Insertion case #3: rotating by grandparent");
} }
@ -89,7 +89,7 @@ class RBTree extends RankedTree {
// Case 1 // Case 1
// ====== // ======
// xs sibling w is red // xs sibling w is red
rotateLeft(parent, this); rotateLeft(this, parent);
this.record("Deletion case #1: rotating by parent", parent); this.record("Deletion case #1: rotating by parent", parent);
w = right(parent); w = right(parent);
} }
@ -107,7 +107,7 @@ class RBTree extends RankedTree {
// xs sibling w is black, // xs sibling w is black,
// ws left child is red, and ws right child is black // ws left child is red, and ws right child is black
if (nodeDifference(right(w), w) == BLACK) { if (nodeDifference(right(w), w) == BLACK) {
rotateRight(w, this); rotateRight(this, w);
this.record("Deletion case #3: rotating by w", w); this.record("Deletion case #3: rotating by w", w);
w = right(parent); w = right(parent);
} }
@ -122,7 +122,7 @@ class RBTree extends RankedTree {
); );
w.rank++; w.rank++;
this.record("Deletion case #4: coloring w's child", w); this.record("Deletion case #4: coloring w's child", w);
rotateLeft(parent, this); rotateLeft(this, parent);
this.record("Deletion case #4: rotating by parent", parent); this.record("Deletion case #4: rotating by parent", parent);
x = this.root; x = this.root;

19
wavl.js
View file

@ -21,7 +21,7 @@ class WAVLTree extends AVLTree {
); );
} }
fixDelete(x, y, z, reversed, rotatingAroundRoot, rotateLeft, rotateRight) { fixDelete(x, y, z, reversed, rotateLeft, rotateRight) {
let newRoot = x; let newRoot = x;
let [v, w] = [y.left, y.right]; let [v, w] = [y.left, y.right];
@ -30,13 +30,9 @@ class WAVLTree extends AVLTree {
} }
let wDiff = nodeDifference(w, y); let wDiff = nodeDifference(w, y);
if (wDiff == 1 && y.parent) { if (wDiff == 1 && y.parent) {
let oldRoot = y.parent; let oldRoot = y.parent;
newRoot = rotateLeft(y.parent); newRoot = rotateLeft(this, y.parent);
if (rotatingAroundRoot) {
this.root = newRoot;
}
this.record( this.record(
"Final step of deletion rebalance: single rotation by parent of y", "Final step of deletion rebalance: single rotation by parent of y",
oldRoot, oldRoot,
@ -58,7 +54,7 @@ class WAVLTree extends AVLTree {
} }
} else if (wDiff == 2 && v && v.parent) { } else if (wDiff == 2 && v && v.parent) {
let oldRoot = v.parent; let oldRoot = v.parent;
let intermediateRoot = rotateRight(v.parent); let intermediateRoot = rotateRight(this, v.parent);
this.record( 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",
oldRoot, oldRoot,
@ -66,10 +62,7 @@ class WAVLTree extends AVLTree {
); );
oldRoot = v.parent; oldRoot = v.parent;
newRoot = rotateLeft(v.parent); newRoot = rotateLeft(this, v.parent);
if (rotatingAroundRoot) {
this.root = newRoot;
}
this.record( 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",
oldRoot, oldRoot,
@ -132,8 +125,6 @@ class WAVLTree extends AVLTree {
return; return;
} }
let rotatingAroundRoot = parent.parent == null;
let parentNodeDiffs = nodeDifferences(parent); let parentNodeDiffs = nodeDifferences(parent);
if (parentNodeDiffs.sort().equals([1, 3])) { if (parentNodeDiffs.sort().equals([1, 3])) {
if (parent.left === x) { if (parent.left === x) {
@ -142,7 +133,6 @@ class WAVLTree extends AVLTree {
parent.right, parent.right,
parent, parent,
false, false,
rotatingAroundRoot,
rotateLeft, rotateLeft,
rotateRight rotateRight
); );
@ -152,7 +142,6 @@ class WAVLTree extends AVLTree {
parent.left, parent.left,
parent, parent,
true, true,
rotatingAroundRoot,
rotateRight, rotateRight,
rotateLeft rotateLeft
); );