165 lines
3.6 KiB
JavaScript
165 lines
3.6 KiB
JavaScript
|
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!";
|
||
|
}
|
||
|
}
|