Computer Science

Strongly Connected Components

Partition a directed graph by mutual reachability, replay two-pass DFS and contract its strongly connected components into a DAG.

By Riano · Published · Report a correction

Strongly Connected Components

A route there and back

A directed arrow grants travel in one direction. Two vertices belong to the same strongly connected component, or SCC, exactly when each can reach the other by a directed path. A component is maximal: every vertex mutually reachable with its members is included. A single outgoing route does not establish strong connectivity.

Why the groups form a partition

Write u ~ v when u reaches v and v reaches u. Zero-edge paths make this relation reflexive, reversing the two claims makes it symmetric, and joining paths makes it transitive. Its equivalence classes partition every vertex, including isolated vertices. A singleton needs no self-loop to be an SCC.

Replace each class by one vertex. Keep an arrow between different classes when an original arrow crosses between them, dropping duplicates and all internal arrows. This condensation cannot contain a directed cycle: a cycle of classes would provide return paths joining those classes into one SCC. The original graph can still have cycles, including a self-loop in a singleton class.

Worked example: three groups, one-way connections

This original six-vertex example uses seven arrows: 0→1, 1→2, 2→0, 2→3, 3→4, 4→3 and 4→5. The first three vertices form a cycle, vertices 3 and 4 can return to each other, and vertex 5 has no outgoing arrow. Enumerating reachability gives the following maximal classes.

Canonical IDMembersReturn-path reason
C00, 1, 20→1→2→0 completes a directed cycle.
C13, 4Both 3→4 and 4→3 are present.
C25The zero-edge path reaches 5 itself; no return to another vertex exists.

There are three SCCs and the largest has three vertices. Only 2→3 and 4→5 cross between classes, so the condensation is C0→C1→C2 with two arrows. The shortest 0-to-5 route is 0→1→2→3→4→5. There is no 5-to-0 route: reaching a downstream component once does not merge the groups.

A single arrow changes the partition

Add 5→0. Every vertex can now follow the cycle through all six vertices and return, giving one SCC, largest size six and zero condensation arrows. Instead, remove 2→0 from the original example: 0, 1 and 2 become separate singleton classes, leaving five SCCs in total and a four-arrow condensation chain.

Trace the two searches

With roots and neighbors examined in ascending order, the first DFS follows 0, 1, 2, 3, 4, 5. Vertices finish in the opposite order: 5, 4, 3, 2, 1, 0. Search the transpose with roots considered as 0, 1, 2, 3, 4, 5. The first new tree reaches 0, 2, 1; the next reaches 3, 4; the last contains 5. These trees recover exactly the reachability classes calculated above.

Kosaraju: finish first, then reverse

The first DFS records each vertex only when its recursive call exits. Reverse that list, reverse every arrow to make the transpose GT, clear the visited marks, and run DFS again using that root order. Skip already assigned vertices. Each new tree in this second search identifies one whole SCC. Transposition preserves mutual reachability while the finish order prevents the new search from spilling into an unassigned neighboring component.

  1. Search all of G, starting a fresh DFS whenever an unvisited vertex remains.
  2. Append a vertex to postorder after all its outgoing neighbors have been considered.
  3. Search GT with roots in reverse postorder; each new tree gets a new component.

The module labels classes by their smallest member: C0 has the smallest minimum, then C1, and so on. This convention is separate from discovery order. For the DAG fork preset the reverse exit order is 0, 2, 1, 3, 4, while canonical singleton IDs and the smallest-available-ID topological order are 0, 1, 2, 3, 4. Neither set of labels changes which vertices are mutually reachable.

Experiment with the native controls

Open the interactive Strongly Connected Components module. The graph and final partition are available immediately; the replay separately exposes the algorithm's intermediate stack and discovered trees.

  1. Choose Cycle chain under Graph example. Confirm three SCCs, seven unique arrows and two condensation arrows. With From vertex 0 and To vertex 5, read a forward path and no reverse path.
  2. Choose Condensation DAG under Graph view. The native graph contracts to C0, C1 and C2. Change to Transpose graph: every original arrow reverses, but the final partition remains unchanged. The query cards continue to describe original G.
  3. Return to Original graph and press Next step. The active white ring moves to vertex 0. Use Play scan, pause, or Finish scan to inspect the exit list and the three second-pass trees. Rewind scan returns the cursor to zero without changing the graph.
  4. Append a new line 5 0 in Directed edges. Watch the six vertices acquire one component color, read SCC count one and see the return path 5→0. The edited graph starts a fresh replay.
  5. Press Reset example, then append 0 3 and 1 4 on separate lines. There are nine unique original arrows, but still two condensation arrows: three different arrows from C0 to C1 collapse to one.
  6. Drag a node to rearrange it and drag the background to pan. Reset view or Home restores the camera; Reset layout also restores automatic node positions. Neither changes the graph. Use the visible vertex buttons as a keyboard alternative for selecting the query source.

Assumptions, boundaries and costs

This is an unweighted, static directed graph model bounded to one through eight vertices for inspection. Reachability and membership use exact integer vertex IDs, with no numerical approximation or random simulation. Changing an arrow recomputes the model; this is not an incremental SCC data structure.

  • Vertex count accepts decimal digits only. Each nonempty edge line contains exactly two nonnegative integer IDs below that count. Empty lines are ignored, duplicate arrows count once, and self-loops are accepted. Invalid raw text stays visible while previous results and the diagram disappear.
  • Self queries have a path of length zero. An isolated vertex is one SCC; a self-loop does not add another class. All singleton classes do not by themselves prove the original graph acyclic, because singleton self-loops are allowed.
  • Shortest query witnesses use ascending-neighbor BFS, so one representative path is shown when several tie. SCC membership does not depend on which shortest witness is chosen. Undirected or weak connectivity ignores arrow direction and answers a different question.
  • The two DFS passes take O(V + E) time with adjacency lists. This teaching implementation also sorts neighbors and canonical labels, copies small replay snapshots, computes query paths and draws the graph. These extra costs are outside the linear core algorithm claim.
  • Node positions, distances and component colors have no graph-theoretic weight. A crossing of drawn arrows creates no vertex. Drags keep node centers separated so their rings and arrow endpoints remain distinct. Reciprocal arrows bend apart; self-loops curve above their vertex. Dense custom graphs can still have overlapping arrows, so use the explicit edge list and path witnesses to resolve direction.
  • Replay colors show the final partition from the start. The active white ring and gold stack rings show the current frame, and the discovered-tree text shows only second-pass assignments made so far. Manual navigation and input changes cancel playback timers.

Primary course references

These references support the definitions and algorithm. The six-vertex worked example, edits, exact partitions and native-control experiment above were calculated independently for this module.

Experience it interactively

Adjust parameters, observe in real time, and build deep intuition with Riano’s interactive Strongly Connected Components module.

Try Strongly Connected Components on Riano →

More in Computer Science