Topological sort and dependency order
Order tasks so nothing runs before what it depends on — and detect the cycle that makes it impossible.
Given a directed acyclic graph of dependencies, a topological order lists every vertex before all the vertices it points to. Build systems, package managers, course prerequisites, task schedulers and spreadsheet recalculation all run this algorithm.
Kahn's algorithm — BFS on in-degrees
Repeatedly take a vertex with nothing left pointing at it.
function topologicalSort(graph) {
const inDegree = new Map([...graph.keys()].map((node) => [node, 0]));
for (const [, edges] of graph) {
for (const next of edges) inDegree.set(next, (inDegree.get(next) ?? 0) + 1);
}
// Everything with no remaining prerequisites can start now.
const queue = [...inDegree].filter(([, degree]) => degree === 0).map(([node]) => node);
const order = [];
while (queue.length) {
const node = queue.shift();
order.push(node);
for (const next of graph.get(node) ?? []) {
inDegree.set(next, inDegree.get(next) - 1);
if (inDegree.get(next) === 0) queue.push(next); // its last blocker cleared
}
}
// Anything left is stuck in a cycle.
return order.length === inDegree.size ? order : null;
}
O(V + E). The length check at the end is the cycle detector — a graph with a cycle can never drain the queue. Returning null rather than a partial order is the honest interface.
DFS alternative
Run DFS and push each vertex onto a list after its descendants finish; reverse the list. It is shorter, and it detects cycles with the three-colour scheme from the previous lesson.
Where it pays
- Build order. Compile dependencies before dependents.
- Task scheduling. With parallelism: everything at in-degree zero can run simultaneously, so the number of Kahn rounds is the minimum number of stages.
- Course prerequisites. "Can this curriculum be finished?" is the cycle check.
- Deadlock detection. A cycle in a resource-wait graph is a deadlock.
The follow-ups
Ask about uniqueness: an order is unique only if exactly one vertex has in-degree zero at every step. Otherwise many valid orders exist, and if the question wants the lexicographically smallest, swap the queue for a min-heap.
For a DAG, the same in-degree sweep also gives the longest path in linear time — which is the critical path of a project schedule, and one of the few graphs where longest path is not intractable.