Skip to content
Part IA Lent Term

Kosaraju's Algorithm

Overview

Kosaraju's algorithm: two strongly connected components separated by a bridge edge

Kosaraju’s algorithm finds all strongly connected components (SCCs) of a directed graph in Θ(V+E)\Theta(|V| + |E|) time using two complete passes of DFS. It is elegant and requires only basic DFS, making it a natural exam topic.

Algorithm: Three Steps

  1. DFS on GG: Run a full DFS on the original graph GG. Record the finish time f[v]f[v] for every vertex.
  2. Transpose: Compute the transpose graph GTG^T: reverse the direction of every edge. VT=VV^T = V, ET={(v,u)(u,v)E}E^T = \{(v,u) \mid (u,v) \in E\}.
  3. DFS on GTG^T: Run DFS on GTG^T, 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 GG.

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 GTG^T in decreasing finish-time order produce SCCs?

  • In step 1, DFS on GG 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 GG becomes a source SCC in GTG^T. Since we process vertices in decreasing finish order, we start DFS from a vertex in the “last-finishing” component (a sink in GG, source in GTG^T). 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 uu and vv are mutually reachable in GG, they remain mutually reachable in GTG^T.

Worked Example

Graph with V={1,2,3,4,5,6,7,8}V = \{1,2,3,4,5,6,7,8\} and edges (as in the SCC notes):

121 \to 2, 232 \to 3, 242 \to 4, 313 \to 1, 343 \to 4, 434 \to 3, 545 \to 4, 565 \to 6, 656 \to 5, 676 \to 7, 787 \to 8, 868 \to 6, 878 \to 7.

Step 1: DFS on GG, start at 1 (assume adjacency list order as listed). Discovery/finish times:

Vertex12345678
dd1234121385
ff1615107111496

(Values depend on adjacency order; any valid DFS is fine.) Decreasing finish order: 1,2,6,5,3,7,4,81, 2, 6, 5, 3, 7, 4, 8.

Step 2: GTG^T. All edges reversed: 212 \to 1, 323 \to 2, 424 \to 2, 131 \to 3, 434 \to 3, 343 \to 4, 454 \to 5, 656 \to 5, 565 \to 6, 767 \to 6, 878 \to 7, 686 \to 8, 787 \to 8.

Step 3: DFS on GTG^T, order: 1, 2, 6, 5, 3, 7, 4, 8.

  • Start from 1 (first in order). DFS from 1 reaches {1,3,4,2}\{1,3,4,2\}. This is SCC {1,2,3,4}\{1,2,3,4\}.
  • Next unvisited in order: 6. DFS from 6 reaches {6,5,8,7}\{6,5,8,7\}. This is SCC {5,6,7,8}\{5,6,7,8\}.
  • Result: two SCCs as expected.

Time Complexity

  • DFS on GG: Θ(V+E)\Theta(|V| + |E|).
  • Computing GTG^T: Θ(V+E)\Theta(|V| + |E|) (reverse every edge).
  • DFS on GTG^T: Θ(V+E)\Theta(|V| + |E|).
  • Total: Θ(V+E)\Theta(|V| + |E|) — 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 C1C_1 and C2C_2 be two distinct SCCs of GG with an edge from C1C_1 to C2C_2 in the component DAG. In step 1, all vertices in C1C_1 finish after all vertices in C2C_2, assuming C1C_1 is explored first. More formally, the finish-time ordering corresponds to a reverse topological sort of the component DAG. Thus, when we process GTG^T in decreasing finish order, we first explore a sink SCC of GG (now a source in GTG^T), and edges to other SCCs point the opposite way in GTG^T, so the DFS stays within the current SCC. The official proof is in CLRS Chapter 22.

Summary

StepActionTime
1DFS on GG, record f[v]f[v]Θ(V+E)\Theta(V+E)
2Construct GTG^TΘ(V+E)\Theta(V+E)
3DFS on GTG^T, decreasing f[v]f[v] orderΘ(V+E)\Theta(V+E)
TotalΘ(V+E)\Theta(V+E)

Past paper questions: SCCs are assessed conceptually; Kosaraju’s algorithm may appear as a direct algorithm question or as part of a larger problem.