Skip to content

Expert: advanced patterns and interviews · Graphs · topic 44 of 61 · 35 min

Topological sort

Explanation

A topological order lists the vertices of a directed graph so that every edge u → v has u before v, like doing prerequisites before the courses that need them. It exists only when the graph has no cycle (a DAG). Kahn's algorithm repeatedly takes vertices with in-degree 0 using a queue; if the output is shorter than n, there is a cycle. Both Kahn and the DFS method run in O(V + E).

Ordering things that depend on each other

Many tasks must happen in a certain order. You must study Data Structures before Algorithms. A build tool must compile code before it links and packages it. In a recipe for masala chai, you boil the water before adding the tea leaves, and add the leaves before straining. Each rule "u must come before v" is a directed edge u → v.

A topological order (or topological sort) is a list of all the vertices in which every edge points forward: for each edge u → v, u appears before v. There are often many valid orders. If the graph has a cycle, such as "A before B" and "B before A", no order can work.

A directed graph with no cycle is called a DAG (directed acyclic graph). Every DAG has at least one topological order, and a directed graph has a topological order only if it is a DAG.

Kahn's algorithm (BFS style)

The in-degree of a vertex is the number of edges coming into it: how many things must happen before it. A vertex with in-degree 0 has nothing blocking it, so it can go first.

  1. Count the in-degree of every vertex.
  2. Put every vertex with in-degree 0 into a queue.
  3. Take a vertex u from the queue and append it to the order.
  4. For every edge u → v, remove that edge by lowering the in-degree of v by 1. If it becomes 0, put v in the queue.
  5. Repeat until the queue is empty. If the order has fewer than n vertices, the graph has a cycle.
python
from collections import deque

def kahn(n, edges):
    adj = [[] for _ in range(n)]
    indeg = [0] * n
    for u, v in edges:
        adj[u].append(v)
        indeg[v] += 1
    queue = deque(u for u in range(n) if indeg[u] == 0)
    order = []
    while queue:
        u = queue.popleft()
        order.append(u)
        for v in adj[u]:
            indeg[v] -= 1
            if indeg[v] == 0:
                queue.append(v)
    return order if len(order) == n else []

print(kahn(4, [(0, 1), (0, 2), (1, 3), (2, 3)]))   # Output: [0, 1, 2, 3]
print(kahn(2, [(0, 1), (1, 0)]))                   # Output: []
O(V + E) time and O(V + E) space. An empty result here means "there is a cycle".

Why does a cycle leave vertices behind? Every vertex on a cycle has an incoming edge from another vertex on the same cycle. None of them can be the first to reach in-degree 0, so none of them ever enters the queue.

The DFS method

Run the three-colour DFS from topic 3. When a vertex FINISHES (all the vertices after it are done), append it to a list. That list is the post-order. Reverse it and you have a topological order, because a vertex always finishes after everything it points to. Meeting a grey vertex means a cycle.

python
def topo_dfs(n, edges):
    adj = [[] for _ in range(n)]
    for u, v in edges:
        adj[u].append(v)
    state = [0] * n          # 0 new, 1 on the path, 2 done
    post = []

    def dfs(u):
        state[u] = 1
        for v in adj[u]:
            if state[v] == 1:
                raise ValueError("cycle")
            if state[v] == 0:
                dfs(v)
        state[u] = 2
        post.append(u)

    for u in range(n):
        if state[u] == 0:
            dfs(u)
    return post[::-1]

print(topo_dfs(4, [(0, 1), (0, 2), (1, 3), (2, 3)]))   # Output: [0, 2, 1, 3]
A different valid order from Kahn's: both put 0 first and 3 last.

Deterministic orders and levels

When several vertices have in-degree 0 at the same time, Kahn's algorithm may take them in any order. If a problem asks for the lexicographically smallest order (the smallest number first whenever there is a choice), replace the queue with a min-heap from heapq (Module 8). The cost grows to O(V log V + E).

Another common question: if you can do any number of ready tasks at once, how many rounds do you need? Run Kahn's algorithm one layer at a time, like level-by-level BFS. The number of layers is the answer, for example the minimum number of semesters to finish a set of courses.

Tip: Python 3.9 and later include graphlib.TopologicalSorter in the standard library. It is handy in real code; in interviews, write Kahn's algorithm yourself.

Common mistakes

  • Reversing the edge direction. In the course-schedule problem, [a, b] usually means "to take a you must first take b", so the edge is b → a. Fix: write the arrow down before coding.
  • Forgetting the cycle check. Fix: compare len(order) with n at the end.
  • Starting only from vertex 0 instead of from every vertex with in-degree 0. Fix: fill the queue with all of them.
  • In the DFS method, forgetting to reverse the post-order. Fix: return post[::-1].
  • Expecting one fixed answer when many orders are valid. Fix: if tests need one answer, use the heap version or check validity instead.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Topological sort · 1/8

Topological sort

This lesson is about topological sort: putting tasks in an order that respects every "this before that" rule.

Prefer a video by a teacher? Find free videos on “topological sort kahn algorithm course schedule explained” on YouTube ↗

In real life: In which order should packages be installed?

A package manager such as pip or npm must install every dependency before the package that needs it. It builds a dependency graph and installs in a topological order; if two packages need each other, it reports a dependency cycle. In the small made-up project below, "app" needs "web" and "db", and "web" needs "http". A heap makes the order deterministic: when several packages are ready, the alphabetically smallest goes first.

python
import heapq

needs = {"app": ["web", "db"], "web": ["http"], "db": [], "http": []}
indeg = {p: len(deps) for p, deps in needs.items()}
used_by = {p: [] for p in needs}
for p, deps in needs.items():
    for d in deps:
        used_by[d].append(p)
ready = [p for p in needs if indeg[p] == 0]
heapq.heapify(ready)
order = []
while ready:
    p = heapq.heappop(ready)
    order.append(p)
    for q in used_by[p]:
        indeg[q] -= 1
        if indeg[q] == 0:
            heapq.heappush(ready, q)
print(order)
Shows ['db', 'http', 'web', 'app']: every package comes after the packages it needs.

Practice (0/3 done)

Task 1 · Code · Python

There are num_courses courses labelled 0 to num_courses − 1. prerequisites is a list of pairs [a, b] meaning "to take course a you must first finish course b" (so the edge is b → a). Write can_finish(num_courses, prerequisites) that returns True if all courses can be finished, i.e. there is no cycle. Use Kahn's algorithm. Example: can_finish(2, [[1, 0], [0, 1]]) returns False.

Task 2 · Code · Python

Write topo_order(n, edges) for a directed graph with vertices 0 to n − 1, where each pair (u, v) means u must come before v. Return the lexicographically smallest topological order: whenever several vertices are ready, take the smallest number first (use heapq instead of a queue). If the graph has a cycle, return []. Example: topo_order(4, [(3, 0), (2, 0)]) returns [1, 2, 3, 0].

Task 3 · Code · Python

There are n courses labelled 0 to n − 1, and relations is a list of pairs (a, b) meaning a must be finished in an EARLIER semester than b. You may take any number of courses in one semester. Write min_semesters(n, relations) that returns the minimum number of semesters to finish all courses, or -1 if it is impossible (a cycle). n = 0 needs 0 semesters. Process Kahn's algorithm one layer at a time.

Quick quiz

Question 1

1.Which graphs have a topological order?

Question 2

2.Kahn's algorithm outputs 4 vertices of a 6-vertex graph. What does that tell you?

Question 3

3.A prerequisite pair [a, b] means "to take a, first finish b". Which edge do you add?

Question 4

4.In the DFS method, how do you get the topological order?

Question 5

5.Why use heapq instead of a deque in Kahn's algorithm?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which graphs have a topological order?

Answer: Directed graphs with no cycle (DAGs)

A cycle means every vertex on it must come before another vertex on it, which is impossible.

Kahn's algorithm outputs 4 vertices of a 6-vertex graph. What does that tell you?

Answer: The graph has a cycle

Vertices on a cycle never reach in-degree 0, so they are left out.

A prerequisite pair [a, b] means "to take a, first finish b". Which edge do you add?

Answer: b → a

b must come before a, and edges point from "before" to "after".

In the DFS method, how do you get the topological order?

Answer: Reverse the finish (post-order) list

A vertex finishes after everything it points to, so the reversed finish order puts it first.

Why use heapq instead of a deque in Kahn's algorithm?

Answer: To get the smallest valid order when several vertices are ready

The heap always hands out the smallest ready vertex, giving one deterministic order.

An undirected graph has 5 edges. What do all the degrees add up to?Related

Answer: 10

Every edge touches two vertices, so it adds 2 to the total: 2 × 5 = 10.

From Graphs: vertices, edges and how to store them

Directed edges 0→1, 0→2, 1→3, 2→3. A DFS from 0 meets vertex 3 a second time. Is there a cycle?Related

Answer: No: 3 is finished (black), not on the current path

Only an edge to a grey vertex (on the current path) closes a cycle. This is a diamond.

From Depth-first search (DFS)

How many edges does a spanning tree of a connected graph with 10 vertices have?Related

Answer: 9

A tree on V vertices always has V − 1 edges.

From Minimum spanning trees

In word ladder, what are the vertices and the edges?Related

Answer: Words; two words that differ in exactly one letter

It is an implicit graph whose edges are generated by changing one letter.

From Graph problem patterns

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Graphs” before its exam: Shortest paths: Dijkstra and friends, Graph problem patterns.
  2. Module 9 exam: Graphs · 14 questions · 25 min, without help. 6 topics of this module still to finish first.
  3. Then the next module, Tries, union-find and bit manipulation. 61 topics left in the course before the final exam.

← Previous: Depth-first search (DFS)