class Queue { constructor() { this.q = []; } enqueue(x) { this.q.push(x); } dequeue() { return this.q.shift(); } isEmpty() { return this.q.length == 0; } } class RankedTree { constructor() { this.root = null; } _getUnwrappedGraph() { let result = ""; let q = new Queue(); q.enqueue(this.root); let edges = []; while (!q.isEmpty()) { let node = q.dequeue(); if (!q) { continue; } result += `"${node.toString()}" [label="${node.value}, ${node.rank}"];\n`; [node.left, node.right].filter(child => child).forEach(child => { edges.push([node, child]); q.enqueue(child); }); } edges.forEach(vertices => { let [u, v] = vertices; result += `"${u.toString()}" -> "${v.toString()}" [label="${nodeDifference(v)}"]\n`; }); return result; } toString() { return `digraph {\n${this._getUnwrappedGraph()}}\n`; } rank() { return nodeRank(this.root); } isCorrect() { return this.isCorrectNode(this.root); } search(value, node) { return nodeSearch(value, node || this.root); } insert(value) { let insertedNode = new Node(value); if (!this.root) { this.root = insertedNode; return; } let parent = findParentNode(value, this.root); if (!parent) { return; } insertedNode.parent = parent; if (value < parent.value) { parent.left = insertedNode; } else { parent.right = insertedNode; } this.insertRebalance(insertedNode); } transplant(u, v) { if (!u.parent) { this.root = v; } else if (u.parent.left === u) { u.parent.left = v; } else { u.parent.right = v; } if (v) { v.rank = u.rank; v.parent = u.parent; } } deleteNode(node) { if (!node) { return null; } let [y, parent] = [null, node.parent]; if (!node.left) { y = node.right; this.transplant(node, node.right); } else if (!node.right) { y = node.left; this.transplant(node, node.left); } else { let successor = nodeMinimum(node.right); parent = successor.parent != node ? successor.parent : successor; if (successor.parent != node) { parent = successor.right ? successor.right : successor.parent; this.transplant(successor, successor.right); successor.right = node.right; successor.right.parent = successor; } this.transplant(node, successor); successor.left = node.left; node.left.parent = successor; } return [y, parent]; } delete(value) { let node = this.root; while (node && node.value != value) { node = value < node.value ? node.left : node.right; } let toRebalance = this.deleteNode(node); if (toRebalance) { let [y, parent] = toRebalance; this.deleteRebalance(y, parent); } } /* abstract methods */ isCorrectNode(node) { throw "not implemented!"; } insertRebalance(node) { throw "not implemented!"; } deleteRebalance(node, parent) { throw "not implemented!"; } }