Expert: advanced patterns and interviews · Graphs · topic 44 of 61 · 35 min
Topological sort
Explanation
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.
- Count the in-degree of every vertex.
- Put every vertex with in-degree 0 into a queue.
- Take a vertex u from the queue and append it to the order.
- 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.
- Repeat until the queue is empty. If the order has fewer than n vertices, the graph has a cycle.
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: []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.
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]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.
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
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.
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)Practice (0/3 done)
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.
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].
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Shortest paths: Dijkstra and friendsGraphs · same module
- Minimum spanning treesTries, union-find and bit manipulation
- Core DSA patterns in C++C++ Programming (modern C++ and DSA) · Competitive programming, interviews and careers
- Traversals: DFS and BFSTrees and binary search trees
- What DSA is, and how to learn itThinking in Big-O
- Stacks and queuesPython Programming · Algorithms, data structures and testing
Questions people ask about this
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.
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.
How many edges does a spanning tree of a connected graph with 10 vertices have?Related
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.
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
- 2 more topics in “Graphs” before its exam: Shortest paths: Dijkstra and friends, Graph problem patterns.
- Module 9 exam: Graphs · 14 questions · 25 min, without help. 6 topics of this module still to finish first.
- Then the next module, Tries, union-find and bit manipulation. 61 topics left in the course before the final exam.