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; } } }