Skip to content
DSA graphs 8 min read

Topological Sort: Kahn's Algorithm & DFS Ordering

A topological sort of a DAG (Directed Acyclic Graph) is a linear ordering of its vertices such that for every directed edge u → v, u comes before v. It answers “in what order can I do these tasks given their dependencies?” — compiling modules, scheduling courses, resolving build steps. A topological order exists if and only if the graph has no cycle; both algorithms below detect that case.

Kahn’s algorithm (BFS / in-degree)

Kahn’s algorithm repeatedly removes vertices that have no remaining prerequisites (in-degree 0):

  1. Compute the in-degree of every vertex.
  2. Put all in-degree-0 vertices in a queue.
  3. Pop one, append it to the order, and decrement the in-degree of each neighbor; if a neighbor drops to 0, enqueue it.
  4. If the final order has fewer than V vertices, the graph had a cycle.
std::vector<int> topoSortKahn(const std::vector<std::vector<int>>& adj) {
    int n = adj.size();
    std::vector<int> indeg(n, 0), order;
    for (int u = 0; u < n; u++) for (int v : adj[u]) indeg[v]++;
    std::queue<int> q;
    for (int i = 0; i < n; i++) if (indeg[i] == 0) q.push(i);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        order.push_back(u);
        for (int v : adj[u]) if (--indeg[v] == 0) q.push(v);
    }
    if ((int)order.size() != n) return {};   // cycle -> no valid order
    return order;
}

Tip: Swap the queue for a min-priority-queue to get the lexicographically smallest topological order — a common interview follow-up.

DFS-based topological sort

Run DFS; when a vertex finishes (all its descendants are processed), push it onto a stack. The reversed finish order is a valid topological order. Intuitively, a vertex finishes only after everything it points to, so it ends up earlier when reversed.

void dfsTopo(int u, const std::vector<std::vector<int>>& adj,
             std::vector<bool>& visited, std::vector<int>& out) {
    visited[u] = true;
    for (int v : adj[u]) if (!visited[v]) dfsTopo(v, adj, visited, out);
    out.push_back(u);                 // push on finish
}
std::vector<int> topoSortDFS(const std::vector<std::vector<int>>& adj) {
    int n = adj.size();
    std::vector<bool> visited(n, false);
    std::vector<int> out;
    for (int i = 0; i < n; i++) if (!visited[i]) dfsTopo(i, adj, visited, out);
    std::reverse(out.begin(), out.end());
    return out;
}

Pitfall: The plain DFS version does not report cycles — on a cyclic graph it still returns an order. If you need cycle safety, prefer Kahn’s algorithm (it naturally returns fewer than V vertices) or add the three-color cycle check to the DFS.

Complexity and uses

Both algorithms run in O(V + E) time and O(V) extra space. Use topological sort for dependency resolution, course scheduling (the classic course schedule problem), build systems, and as a preprocessing step for shortest/longest paths on a DAG.

Next up: weighted shortest paths with Dijkstra’s algorithm.

Last updated June 25, 2026
Was this helpful?