Home/Graphs/Kosaraju
Search algorithmsCTRL K

Kosaraju

· strongly connected components · two passes
/graphs/kosaraju
PHASE
finish order
of the two passes
FINISHED
0/ 10
first pass: nodes finished
COMPONENTS
0
found so far
COLLECTED
0
second pass: nodes placed
LARGEST
0
nodes in the biggest component
currentDFS edgefinished · collectedunvisited
10 nodes · 14 edges · seed 7 · 42 steps
step 0 / 41
Nodes10
kosaraju.ts
1
function kosaraju(graph: Graph) {
2
  const order: Node[] = []; const seen = new Set<Node>();
3
  const finish = (node: Node) => { seen.add(node); for (const next of graph.successors(node)) if (!seen.has(next)) finish(next); order.push(node); };
4
  for (const node of graph.nodes) if (!seen.has(node)) finish(node);
5
  const reversed = graph.reverse();
6
  const components: Node[][] = []; seen.clear();
7
  const collect = (node: Node, component: Node[]) => { seen.add(node); component.push(node); for (const next of reversed.successors(node)) if (!seen.has(next)) collect(next, component); };
8
  for (const node of order.reverse()) {
9
    if (seen.has(node)) continue;
10
    const component: Node[] = []; collect(node, component);
11
    components.push(component);
12
  }
13
  return components;
14
}
CURRENT STEP
line 4

A is unvisited: depth-first search from there, recording when each node finishes.

// how it works

Understanding Kosaraju

Kosaraju · finish order forwards, then collect backwards
01

The idea

Kosaraju's algorithm needs two depth-first searches. The first runs on the graph and records the order in which nodes finish. The second runs on the reversed graph, starting from the nodes that finished last, and every tree it grows is exactly one strongly connected component.

It works because the last node to finish lies in a source component of the condensation, and in the reversed graph a source becomes a sink: the search from it cannot escape its own component. Then the next unvisited latest finisher, and so on. Twice the work of Tarjan, but each pass is a plain DFS.

02

The four stages

1
first passDFS, record the finish order
2
reverseflip every edge
3
second passDFS from the latest finisher still unvisited
4
collecteach tree is one component
03

Complexity

best
O(V + E)two linear passes
average
O(V + E)plus building the reversed graph
worst
O(V + E)the same
space
O(V + E)the reversed adjacency lists
04

Versus its siblings

EDGE VISITS · 1 000 NODES, 3 000 EDGES
tarjan
4,000
kosaraju
8,000
naive (bfs per node)
4M
Kosaraju visits every edge twice, once per direction
05

Pseudocode

KOSARAJU(graph)
  first pass: DFS the graph; append each node to `order` when it finishes
  reverse every edge
  second pass: for each node in decreasing finish order, if unvisited
    DFS on the reversed graph from it; every node reached is one component
06

When to use

When the reversed graph is already available or cheap: adjacency matrices, databases with both link directions indexed.
Teaching: the correctness argument is short and the two passes are ordinary DFS.
07

Pitfalls

The second pass must go in decreasing finish time; increasing order merges components.
Reversing a big edge list costs memory; Tarjan avoids it.
Components are produced in topological order of the condensation, the reverse of Tarjan's.
08

History

S. Rao Kosaraju described the two-pass method in unpublished lecture notes in 1978; Micha Sharir published it independently in 1981. It is the algorithm most textbooks teach first because its proof fits on a page, even though Tarjan's single pass from 1972 is faster.

Back to Graphs