Topological sort — DFS-based, Kahn's algorithm (BFS-based)
WHAT is a topological sort?
WHY does a cycle break it? If , then must come before , before , and before . That forces before — impossible. So cycles ⇒ no topological order.
WHY two algorithms?
Both solve the same problem but think differently:
| DFS-based | Kahn's (BFS-based) | |
|---|---|---|
| Core idea | A node finishes after all its descendants | Repeatedly remove nodes with no remaining prerequisites |
| Output built | In reverse finish order | In arrival order |
| Cycle detection | Back edge (gray node) | Fewer than $ |
| Data structure | Recursion stack | Queue + indegree array |
Both run in .
Algorithm 1 — DFS-based
HOW it works (derivation from first principles)
Claim: If we reverse the order in which DFS finishes vertices, every edge points forward.
Take any edge . When DFS first touches , consider 's state:
- unvisited: DFS will explore as a descendant of , so finishes before . ✅ ( finishes later ⇒ earlier in reversed order)
- already finished: then finished before even started. ✅
- in progress (gray, on the stack): this means there's a path already, plus edge = a cycle. Not allowed in a DAG. ❌ blocked.
In every valid (DAG) case, finishes after , so in the reversed finish list precedes . Edge points forward. ∎
function topoDFS(G):
visited = {}, finished = []
for each vertex u in V:
if u not visited: dfs(u)
return reverse(finished)
function dfs(u):
mark u visited (GRAY)
for each edge u -> v:
if v GRAY: report CYCLE # back edge
if v not visited: dfs(v)
mark u BLACK
finished.append(u) # append on FINISH
Algorithm 2 — Kahn's Algorithm (BFS-based)
HOW it works (derivation)
Define = number of edges pointing into .
- A DAG always has at least one vertex with indegree 0 (else follow incoming edges backward forever ⇒ a repeat ⇒ cycle). So we can always start.
- Emitting a 0-indegree vertex and deleting its out-edges keeps the rest a DAG. By induction the whole graph empties out.
- Every edge points forward: when we emit , all of 's prerequisites are already emitted; the edge decrements , so is emitted strictly later. ✅
function kahn(G):
compute indeg[v] for all v
Q = queue of all v with indeg[v] == 0
order = []
while Q not empty:
u = Q.pop()
order.append(u)
for each edge u -> v:
indeg[v] -= 1
if indeg[v] == 0: Q.push(v)
if len(order) < |V|: report CYCLE # leftover nodes stuck in a cycle
return order

Worked Example (same graph, both methods)
Graph edges:
5→0, 5→2, 4→0, 4→1, 2→3, 3→1
Vertices: 0 1 2 3 4 5
Kahn's walk-through
Indegrees: 0:2, 1:2, 2:1, 3:1, 4:0, 5:0
| Step | Queue (indeg 0) | Pop | Emit | Updates |
|---|---|---|---|---|
| 1 | [4, 5] | 4 | 4 | 0→1, 1→1 |
| 2 | [5] | 5 | 5 | 0→0✅, 2→0✅ |
| 3 | [0, 2] | 0 | 0 | — |
| 4 | [2] | 2 | 2 | 3→0✅ |
| 5 | [3] | 3 | 3 | 1→0✅ |
| 6 | [1] | 1 | 1 | — |
Order: 4 5 0 2 3 1 — Why this step? We always pulled an indegree-0 node, guaranteeing every prerequisite was already out. 6 emitted = |V| ⇒ valid DAG.
DFS walk-through (start at 5, then 4)
- dfs(5)→dfs(0) finish 0 →dfs(2)→dfs(3)→dfs(1) finish 1, finish 3, finish 2, finish 5
- dfs(4): 0,1 done → finish 4
- finished list =
[0,1,3,2,5,4] - Reverse = 4 5 2 3 1 0
Why this step? We append each node only after its descendants finished, so reversing puts roots first. (Note: different valid order from Kahn — both correct!)
Common Mistakes
Active Recall
Recall Quick self-test (cover the answers)
- When does a topological order exist? → iff the graph is a DAG.
- In DFS-topo, when do you record a node? → on finish, then reverse.
- Kahn's start set? → all vertices with indegree 0.
- Both algorithms' complexity? → .
- How does each detect a cycle? → DFS: back edge to a gray node. Kahn: emitted count .
Recall Feynman: explain to a 12-year-old
Imagine you have homework tasks where some must be done before others — you can't write the essay before reading the book. A topological sort lines up all tasks so you never do a later task before its required earlier one. Way 1 (DFS): dive into a task and all the tasks it leads to first; the moment you fully finish a task, drop it in a "done" pile. The pile is upside down, so flip it. Way 2 (Kahn): keep doing any task that has no leftover requirements; each time you finish one, cross it off its followers' lists — some followers now have zero requirements and become doable. If you get stuck with tasks still left, they depend on each other in a loop and can't be ordered.
Connections
- Depth-First Search (DFS) — DFS-topo is just DFS + finish-time ordering.
- Breadth-First Search (BFS) — Kahn's is BFS driven by indegree.
- Directed Acyclic Graph (DAG) — the precondition for any topo order.
- Cycle Detection in Directed Graphs — both algorithms detect cycles as a byproduct.
- Course Schedule Problem — classic application of topological sort.
- Shortest Path in DAG — relax edges in topological order for shortest paths.
- Strongly Connected Components — Kosaraju uses DFS finish ordering similarly.
What is a topological ordering of a DAG?
A topological ordering exists if and only if the graph is...?
In DFS-based topo sort, when is a vertex recorded?
Why does reversing DFS finish order give a topo sort?
What set of vertices initializes Kahn's queue?
In Kahn's algorithm, when do you push a neighbour onto the queue?
How does Kahn's algorithm detect a cycle?
How does DFS-based topo sort detect a cycle?
Time complexity of both topological sort algorithms?
Is the topological order unique?
Why must a DAG have at least one indegree-0 vertex?
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Topological sort ka matlab hai: ek directed graph (DAG) ke vertices ko ek line me aise arrange karna ki har edge u→v ke liye u hamesha v se pehle aaye. Socho tasks hain — pehle book padho phir essay likho. Yeh ordering sirf tabhi possible hai jab graph me koi cycle na ho (DAG ho). Cycle hone par a→b→c→a jaisi situation banti hai, jisme har cheez khud se pehle aani padti hai — impossible.
Do tareeke hain. DFS-based: node ko tab record karo jab woh finish ho (uske saare descendants explore ho gaye). Finish hone par list me daalo, phir poori list reverse kar do. Kyun? Kyunki edge u→v me u hamesha v ke baad finish hota hai, to reverse karne par u aage aa jaata hai. Yaad rakhna — entry pe record mat karo, sirf finish pe.
Kahn's algorithm (BFS-based): har vertex ka indegree (kitne edges andar aa rahe hain) count karo. Jiska indegree 0 hai uske koi prerequisite pending nahi — usko queue me daalo aur emit karo. Emit karte hi uske neighbours ka indegree 1 kam karo; jo bhi 0 ho jaaye usko queue me daalo. Repeat. Agar end me emitted count < |V| hai, matlab graph me cycle hai.
Dono O(V+E) me chalte hain. Mnemonic yaad rakho: "DFS Finishes & Flips, Kahn Counts to Zero." Real life applications — course scheduling, build dependencies, DAG me shortest path. Bahut common interview topic hai, to dono ko haath se ek chhote graph par chala kar dekho.