Purpose

A directed acyclic graph (DAG) is a directed graph with no cycles. DAGs model any dependency structure where work must happen in a legal order: build systems, course prerequisites, and the subproblem structure of dynamic programming. This note proves the basic facts about topological orderings and gives the standard algorithm for computing one.

Topological Orderings

A topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge , we have . Every edge points forward in the ordering. Laid out in topological order, every edge points rightward:

flowchart LR
    v1((v1)) --> v2((v2))
    v1 --> v3((v3))
    v2 --> v4((v4))
    v3 --> v4
    v3 --> v5((v5))
    v4 --> v6((v6))
    v5 --> v6

Lemma: If has a topological ordering, then is a DAG.

Proof: For contradiction, assume has a topological ordering and also a cycle . Let be the vertex of the cycle that appears earliest in the topological ordering. The cycle contains an edge into from its predecessor on the cycle, and that predecessor appears later in the ordering than by choice of . That edge points backward, contradicting the definition of a topological ordering.

Lemma: If is a DAG, then has a source vertex, i.e. a vertex with .

Proof: Suppose for contradiction that every vertex has . Start at an arbitrary vertex and repeatedly step backward along some incoming edge. Every vertex has an incoming edge, so this walk never gets stuck. The graph has finitely many vertices, so the walk must eventually revisit a vertex, and the segment between the two visits is a cycle. This contradicts being acyclic.

The source lemma does the algorithmic work

Removing a source from a DAG leaves a DAG, so sources never run out until the graph is empty. Kahn’s algorithm below is this lemma applied repeatedly.

Lemma: If is a DAG, then has a topological ordering.

Proof: Induct on the number of vertices. A single vertex is trivially ordered. For vertices, take a source (one exists by the previous lemma), and place it first. Deleting leaves a DAG on vertices, which by the inductive hypothesis has a topological ordering. Appending that ordering after orders all of : edges out of point forward because is first, and has no incoming edges.

Algorithm

The proof above is the algorithm, known as Kahn’s algorithm: repeatedly remove a source and append it to the order. Track indegrees so that finding new sources is cheap. Each vertex and edge is processed once, so the runtime is .

def topological_sort(G):
    indegree = {v: 0 for v in G}
    for v in G:
        for u in G[v]:
            indegree[u] += 1
 
    S = {v for v in G if indegree[v] == 0}
    order = []
 
    while S:
        v = S.pop()
        order.append(v)
        for u in G[v]:
            indegree[u] -= 1
            if indegree[u] == 0:
                S.add(u)
 
    return order

If the loop ends before all vertices are ordered, the remaining vertices all have positive indegree, which means the graph contains a cycle. That makes this algorithm a cycle detector too.