Written by Charlotte Knierim.
Contents
This article assumes you are familiar with digraphs (directed graphs) and have already read the article about Preorder and Postorder.
In this article we look at strongly connected components of digraphs. Given a digraph, it is a natural question which vertices can be reached by a given vertex. A digraph is called strongly connected, if every vertex can be reached from every other vertex.
If a digraph is not strongly connected, then we can decompose it into strongly connected components. These are maximal sets in the graph such that every vertex in a set can be reached by every other vertex from the same set.
Example:
We can display the relationship between the strongly connected components in a component graph. The component graph is a DAG (directed acyclic graph). Note that there is a path from vertex to vertex if and only if there is a path from the component containing to the component containing in the component graph.
Example:
Algorithm by Kosaraju
We show an algorithm that computes the strongly connected components of a digraph in . For this algorithm, we need the transpose that consists of all edges of reversed. Formally we add an edge to if was an edge in .
Note that the strongly connected components of are exactly the same as the strongly connected components of .
Steps of the algorithm:
- Perform a DFS in take note of the postorder of the vertices
- Create the transpose graph
- Perform a DFS in according to the reverse postorder of the vertices
Example: Starting the DFS at visiting and and then and and finally restarting the DFS at (because we cannot reach it from ) gives the following result. The number at each vertex indicates the postorder, the DFS edges are marked in red.
Keeping the postorder in mind, we now create the transposed graph .
On the resulting graph we now perform a DFS starting at the vertex with the highest postorder (here ). Whenever we restart the DFS, we begin a new strongly connected component. Again the DFS edges are indicated in red.
Implementation
Implementation in C++:
struct graph { int n; int num_comp = 0; vector<vector<int>> adjlist; vector<int> post; vector<int> comp; void dfs(int curr, int curr_comp = -2) { if (comp[curr] != -1) return; comp[curr] = curr_comp; for (auto nx : adjlist[curr]) dfs(nx, curr_comp); post.push_back(curr); } void kosaraju() { // Create list of vertices in post order comp.assign(n, -1); for (int i = 0; i < n; i++) dfs(i); // Reverse post order reverse(post.begin(), post.end()); // Build transpose graph vector<vector<int>> rev(n); for (int i = 0; i < n; i++) for (auto j : adjlist[i]) rev[j].push_back(i); swap(rev, adjlist); // Run dfs in reverse post order on transpose graph comp.assign(n, -1); for (int i = 0; i < n; i++) if (comp[post[i]] == -1) dfs(post[i], num_comp++); // Restore original graph swap(rev, adjlist); } };
Remark In the end we have a vector comp such that for any vertex we have that belongs to the strongly connected component comp[v]. We can now build the component graph in by iterating over all edges of and for an edge adding the edge (comp[u],comp[v]) to the component graph if it is not contained already.