function topologicalSort(graph: DAG) {const inDegree = new Map(graph.nodes.map((node) => [node, 0]));
for (const [source, successor] of graph.edges) inDegree.set(successor, inDegree.get(successor)! + 1);
const queue = graph.nodes.filter((node) => inDegree.get(node) === 0);
const order: Node[] = [];
while (queue.length > 0) {const node = queue.shift()!;
order.push(node);
for (const successor of graph.successors(node)) {inDegree.set(successor, inDegree.get(successor)! - 1);
if (inDegree.get(successor) === 0) queue.push(successor);
}
}
return order;
}
Count the incoming edges of every node: A:0 B:1 C:1 D:1 E:4 F:1 G:1 H:1 I:3 J:3.
Understanding Topological sort
The idea
Kahn's algorithm orders the nodes of a directed acyclic graph so that every edge points forward. It counts the incoming edges of each node, starts with the nodes that have none, and repeatedly takes one, appends it to the order, and removes its outgoing edges. Whenever a node's count drops to zero, it becomes available.
If the graph has a cycle the queue empties before every node is placed: no order exists. That makes the same loop a cycle detector, which is how build systems, package managers and spreadsheets refuse circular dependencies.
The four stages
Complexity
Versus its siblings
Pseudocode
KAHN(graph)
inDegree[node] ← number of edges into node, for every node
queue ← every node with inDegree[node] = 0; order ← []
while queue not empty
node ← dequeue; append node to order
for each edge node → successor: inDegree[successor] ← inDegree[successor] − 1; if 0: enqueue successor
if |order| < |V|: the graph has a cycle
When to use
Pitfalls
History
Arthur Kahn published this algorithm in 1962 for scheduling large projects with PERT networks. Tarjan gave the depth-first alternative in 1976, and every build system since make in 1976 has been, at its heart, a topological sort of a dependency graph.