55import java .util .Stack ;
66
77/**
8- * Java program that implements Kosaraju Algorithm.
9- * @author <a href="https://github.com/shivu2002a">Shivanagouda S A</a>
8+ * This class implements the Kosaraju Algorithm to find all the Strongly Connected Components (SCCs)
9+ * of a directed graph. Kosaraju's algorithm runs in linear time and leverages the concept that
10+ * the SCCs of a directed graph remain the same in its transpose (reverse) graph.
11+ *
1012 * <p>
11- * Kosaraju algorithm is a linear time algorithm to find the strongly connected components of a
12- directed graph, which, from here onwards will be referred by SCC. It leverages the fact that the
13- transpose graph (same graph with all the edges reversed) has exactly the same SCCs as the original
14- graph.
15-
16- * A graph is said to be strongly connected if every vertex is reachable from every other vertex.
17- The SCCs of a directed graph form a partition into subgraphs that are themselves strongly
18- connected. Single node is always a SCC.
19-
20- * Example:
21-
22- 0 <--- 2 -------> 3 -------- > 4 ---- > 7
23- | ^ | ^ ^
24- | / | \ /
25- | / | \ /
26- v / v \ /
27- 1 5 --> 6
28-
29- For the above graph, the SCC list goes as follows:
30- 0, 1, 2
31- 3
32- 4, 5, 6
33- 7
34-
35- We can also see that order of the nodes in an SCC doesn't matter since they are in cycle.
36-
37- {@summary}
38- * Kosaraju Algorithm:
39- 1. Perform DFS traversal of the graph. Push node to stack before returning. This gives edges
40- sorted by lowest finish time.
41- 2. Find the transpose graph by reversing the edges.
42- 3. Pop nodes one by one from the stack and again to DFS on the modified graph.
43-
44- The transpose graph of the above graph:
45- 0 ---> 2 <------- 3 <------- 4 <------ 7
46- ^ / ^ \ /
47- | / | \ /
48- | / | \ /
49- | v | v v
50- 1 5 <--- 6
51-
52- We can observe that this graph has the same SCC as that of original graph.
53-
13+ * A strongly connected component (SCC) of a directed graph is a subgraph where every vertex
14+ * is reachable from every other vertex in the subgraph. The Kosaraju algorithm is particularly
15+ * efficient for finding SCCs because it performs two Depth First Search (DFS) passes on the
16+ * graph and its transpose.
17+ * </p>
18+ *
19+ * <p><strong>Algorithm:</strong></p>
20+ * <ol>
21+ * <li>Perform DFS on the original graph and push nodes to a stack in the order of their finishing time.</li>
22+ * <li>Generate the transpose (reversed edges) of the original graph.</li>
23+ * <li>Perform DFS on the transpose graph, using the stack from the first DFS. Each DFS run on the transpose graph gives a SCC.</li>
24+ * </ol>
25+ *
26+ * <p><strong>Example Graph:</strong></p>
27+ * <pre>
28+ * 0 <--- 2 -------> 3 -------- > 4 ---- > 7
29+ * | ^ | ^ ^
30+ * | / | \ /
31+ * | / | \ /
32+ * v / v \ /
33+ * 1 5 --> 6
34+ * </pre>
35+ *
36+ * <p><strong>SCCs in the example:</strong></p>
37+ * <ul>
38+ * <li>{0, 1, 2}</li>
39+ * <li>{3}</li>
40+ * <li>{4, 5, 6}</li>
41+ * <li>{7}</li>
42+ * </ul>
43+ *
44+ * <p>The order of nodes in an SCC does not matter because every node in an SCC is reachable from every other node within the same SCC.</p>
45+ *
46+ * <p><strong>Graph Transpose Example:</strong></p>
47+ * <pre>
48+ * 0 ---> 2 <------- 3 <------- 4 <------ 7
49+ * ^ / ^ \ /
50+ * | / | \ /
51+ * | / | \ /
52+ * | v | v v
53+ * 1 5 <--- 6
54+ * </pre>
55+ *
56+ * The SCCs of this transpose graph are the same as the original graph.
5457 */
55-
5658public class Kosaraju {
5759
58- // Sort edges according to lowest finish time
59- Stack <Integer > stack = new Stack <Integer >();
60+ // Stack to sort edges by the lowest finish time (used in the first DFS)
61+ private final Stack <Integer > stack = new Stack <>();
6062
61- // Store each component
63+ // Store each strongly connected component
6264 private List <Integer > scc = new ArrayList <>();
6365
64- // All the strongly connected components
65- private List <List <Integer >> sccsList = new ArrayList <>();
66+ // List of all SCCs
67+ private final List <List <Integer >> sccsList = new ArrayList <>();
6668
6769 /**
70+ * Main function to perform Kosaraju's Algorithm.
71+ * Steps:
72+ * 1. Sort nodes by the lowest finishing time
73+ * 2. Create the transpose (reverse edges) of the original graph
74+ * 3. Find SCCs by performing DFS on the transpose graph
75+ * 4. Return the list of SCCs
6876 *
69- * @param v Node count
70- * @param list Adjacency list of graph
71- * @return List of SCCs
77+ * @param v the number of vertices in the graph
78+ * @param list the adjacency list representing the directed graph
79+ * @return a list of SCCs where each SCC is a list of vertices
7280 */
7381 public List <List <Integer >> kosaraju (int v , List <List <Integer >> list ) {
74-
7582 sortEdgesByLowestFinishTime (v , list );
76-
7783 List <List <Integer >> transposeGraph = createTransposeMatrix (v , list );
78-
7984 findStronglyConnectedComponents (v , transposeGraph );
80-
8185 return sccsList ;
8286 }
8387
88+ /**
89+ * Performs DFS on the original graph to sort nodes by their finishing times.
90+ * @param v the number of vertices in the graph
91+ * @param list the adjacency list representing the original graph
92+ */
8493 private void sortEdgesByLowestFinishTime (int v , List <List <Integer >> list ) {
8594 int [] vis = new int [v ];
8695 for (int i = 0 ; i < v ; i ++) {
@@ -90,8 +99,14 @@ private void sortEdgesByLowestFinishTime(int v, List<List<Integer>> list) {
9099 }
91100 }
92101
102+ /**
103+ * Creates the transpose (reverse) of the original graph.
104+ * @param v the number of vertices in the graph
105+ * @param list the adjacency list representing the original graph
106+ * @return the adjacency list representing the transposed graph
107+ */
93108 private List <List <Integer >> createTransposeMatrix (int v , List <List <Integer >> list ) {
94- var transposeGraph = new ArrayList <List < Integer > >(v );
109+ List < List < Integer >> transposeGraph = new ArrayList <>(v );
95110 for (int i = 0 ; i < v ; i ++) {
96111 transposeGraph .add (new ArrayList <>());
97112 }
@@ -104,14 +119,14 @@ private List<List<Integer>> createTransposeMatrix(int v, List<List<Integer>> lis
104119 }
105120
106121 /**
107- *
108- * @param v Node count
109- * @param transposeGraph Transpose of the given adjacency list
122+ * Finds the strongly connected components (SCCs) by performing DFS on the transposed graph.
123+ * @param v the number of vertices in the graph
124+ * @param transposeGraph the adjacency list representing the transposed graph
110125 */
111126 public void findStronglyConnectedComponents (int v , List <List <Integer >> transposeGraph ) {
112127 int [] vis = new int [v ];
113128 while (!stack .isEmpty ()) {
114- var node = stack .pop ();
129+ int node = stack .pop ();
115130 if (vis [node ] == 0 ) {
116131 dfs2 (node , vis , transposeGraph );
117132 sccsList .add (scc );
@@ -120,7 +135,12 @@ public void findStronglyConnectedComponents(int v, List<List<Integer>> transpose
120135 }
121136 }
122137
123- // Dfs to store the nodes in order of lowest finish time
138+ /**
139+ * Performs DFS on the original graph and pushes nodes onto the stack in order of their finish time.
140+ * @param node the current node being visited
141+ * @param vis array to keep track of visited nodes
142+ * @param list the adjacency list of the graph
143+ */
124144 private void dfs (int node , int [] vis , List <List <Integer >> list ) {
125145 vis [node ] = 1 ;
126146 for (Integer neighbour : list .get (node )) {
@@ -131,7 +151,12 @@ private void dfs(int node, int[] vis, List<List<Integer>> list) {
131151 stack .push (node );
132152 }
133153
134- // Dfs to find all the nodes of each strongly connected component
154+ /**
155+ * Performs DFS on the transposed graph to find the strongly connected components.
156+ * @param node the current node being visited
157+ * @param vis array to keep track of visited nodes
158+ * @param list the adjacency list of the transposed graph
159+ */
135160 private void dfs2 (int node , int [] vis , List <List <Integer >> list ) {
136161 vis [node ] = 1 ;
137162 for (Integer neighbour : list .get (node )) {
0 commit comments