Kosaraju's Algorithm
Overview
Kosaraju’s algorithm finds all strongly connected components (SCCs) of a directed graph in time using two complete passes of DFS. It is elegant and requires only basic DFS, making it a natural exam topic.
Algorithm: Three Steps
- DFS on : Run a full DFS on the original graph . Record the finish time for every vertex.
- Transpose: Compute the transpose graph : reverse the direction of every edge. , .
- DFS on : Run DFS on , but in the outer loop (which picks the next root), process vertices in decreasing order of their finish times from step 1. Each DFS tree in this forest is one SCC of .
Pseudocode
KOSARAJU(G):
// Step 1: DFS on G, record finish times
for each v in G.V:
v.colour = WHITE
v.π = NIL
time = 0
order = [] // list for finish-time ordering
for each v in G.V:
if v.colour == WHITE:
DFS-VISIT-FINISH(G, v, order)
// Step 2: Compute G^T
GT = TRANSPOSE(G)
// Step 3: DFS on G^T in reverse finish order
for each v in GT.V:
v.colour = WHITE
sccs = []
for each v in reverse(order): // decreasing finish time
if v.colour == WHITE:
component = []
DFS-VISIT-COLLECT(GT, v, component)
sccs.append(component)
return sccs
Intuition
Why does processing in decreasing finish-time order produce SCCs?
- In step 1, DFS on assigns finish times. The SCC that acts as a sink in the component DAG (no outgoing edges to other SCCs) finishes first amongst its DFS tree. More generally, finish times reveal the topological order of the component DAG: components earlier in the topological order finish later.
- In step 3, we reverse all edges. The sink SCC in becomes a source SCC in . Since we process vertices in decreasing finish order, we start DFS from a vertex in the “last-finishing” component (a sink in , source in ). Because edges between SCCs are reversed, the DFS cannot escape this SCC into others that haven’t been visited yet.
- Within an SCC, edges go both ways, so reversing preserves strong connectivity: if vertices and are mutually reachable in , they remain mutually reachable in .
Worked Example
Graph with and edges (as in the SCC notes):
, , , , , , , , , , , , .
Step 1: DFS on , start at 1 (assume adjacency list order as listed). Discovery/finish times:
| Vertex | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 12 | 13 | 8 | 5 | |
| 16 | 15 | 10 | 7 | 11 | 14 | 9 | 6 |
(Values depend on adjacency order; any valid DFS is fine.) Decreasing finish order: .
Step 2: . All edges reversed: , , , , , , , , , , , , .
Step 3: DFS on , order: 1, 2, 6, 5, 3, 7, 4, 8.
- Start from 1 (first in order). DFS from 1 reaches . This is SCC .
- Next unvisited in order: 6. DFS from 6 reaches . This is SCC .
- Result: two SCCs as expected.
Time Complexity
- DFS on : .
- Computing : (reverse every edge).
- DFS on : .
- Total: — linear in the size of the graph.
The algorithm is optimal: any algorithm must at least examine every vertex and edge to find all SCCs.
Correctness Sketch
Let and be two distinct SCCs of with an edge from to in the component DAG. In step 1, all vertices in finish after all vertices in , assuming is explored first. More formally, the finish-time ordering corresponds to a reverse topological sort of the component DAG. Thus, when we process in decreasing finish order, we first explore a sink SCC of (now a source in ), and edges to other SCCs point the opposite way in , so the DFS stays within the current SCC. The official proof is in CLRS Chapter 22.
Summary
| Step | Action | Time |
|---|---|---|
| 1 | DFS on , record | |
| 2 | Construct | |
| 3 | DFS on , decreasing order | |
| Total |
Past paper questions: SCCs are assessed conceptually; Kosaraju’s algorithm may appear as a direct algorithm question or as part of a larger problem.