topological-sort
Version:
Topological sort
74 lines • 2.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
class TopologicalSort {
constructor(nodes) {
this.nodes = new Map();
this.addMultipleInternalNodes(nodes);
}
addNode(key, node) {
return this.addInternalNode(key, node);
}
addNodes(nodes) {
this.addMultipleInternalNodes(nodes);
}
addEdge(fromKey, toKey) {
assert(this.nodes.has(fromKey), `Source node with ${fromKey} key should exist`);
assert(this.nodes.has(toKey), `Target node with ${toKey} key should exist`);
const sourceNode = this.nodes.get(fromKey);
const targetNode = this.nodes.get(toKey);
assert.strictEqual(sourceNode !== undefined, true, `Source node with key ${fromKey} doesn't exist`);
assert.strictEqual(targetNode !== undefined, true, `Target node with key ${toKey} doesn't exist`);
assert.strictEqual(sourceNode.children.has(toKey), false, `Source node ${fromKey} already has an adge to target node ${toKey}`);
sourceNode.children.set(toKey, targetNode);
}
sort() {
this.visitedNodes = new Set();
this.sortedKeysStack = [];
const output = new Map();
for (const [key] of this.nodes) {
this.exploreNode(key, []);
}
for (let i = this.sortedKeysStack.length - 1; i >= 0; i--) {
const node = this.nodes.get(this.sortedKeysStack[i]);
output.set(this.sortedKeysStack[i], node);
}
return output;
}
exploreNode(nodeKey, explorePath) {
const newExplorePath = [...explorePath, nodeKey];
// we should check circular dependencies starting from node 2
if (explorePath.length) {
assert(!explorePath.includes(nodeKey), `Node ${nodeKey} forms circular dependency: ${newExplorePath.join(' -> ')}`);
}
const node = this.nodes.get(nodeKey);
if (this.visitedNodes.has(node)) {
return;
}
// mark node as visited so that it and its children
// won't be explored next time
this.visitedNodes.add(node);
for (const [childNodeKey] of node.children) {
this.exploreNode(childNodeKey, newExplorePath);
}
this.sortedKeysStack.push(nodeKey);
}
addInternalNode(key, node) {
assert.strictEqual(this.nodes.has(key), false, `Node ${key} already exists`);
this.nodes.set(key, {
children: new Map(),
node,
});
return this;
}
addMultipleInternalNodes(nodes) {
const nodesFlat = [...nodes];
for (let i = nodes.size - 1; i >= 0; i--) {
const [key, node] = nodesFlat[i];
this.addInternalNode(key, node);
}
}
}
exports.TopologicalSort = TopologicalSort;
exports.default = TopologicalSort;
//# sourceMappingURL=index.js.map