5
5
import java .util .Stack ;
6
6
7
7
/**
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
+ *
10
12
* <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.
54
57
*/
55
-
56
58
public class Kosaraju {
57
59
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 <>();
60
62
61
- // Store each component
63
+ // Store each strongly connected component
62
64
private List <Integer > scc = new ArrayList <>();
63
65
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 <>();
66
68
67
69
/**
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
68
76
*
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
72
80
*/
73
81
public List <List <Integer >> kosaraju (int v , List <List <Integer >> list ) {
74
-
75
82
sortEdgesByLowestFinishTime (v , list );
76
-
77
83
List <List <Integer >> transposeGraph = createTransposeMatrix (v , list );
78
-
79
84
findStronglyConnectedComponents (v , transposeGraph );
80
-
81
85
return sccsList ;
82
86
}
83
87
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
+ */
84
93
private void sortEdgesByLowestFinishTime (int v , List <List <Integer >> list ) {
85
94
int [] vis = new int [v ];
86
95
for (int i = 0 ; i < v ; i ++) {
@@ -90,8 +99,14 @@ private void sortEdgesByLowestFinishTime(int v, List<List<Integer>> list) {
90
99
}
91
100
}
92
101
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
+ */
93
108
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 );
95
110
for (int i = 0 ; i < v ; i ++) {
96
111
transposeGraph .add (new ArrayList <>());
97
112
}
@@ -104,14 +119,14 @@ private List<List<Integer>> createTransposeMatrix(int v, List<List<Integer>> lis
104
119
}
105
120
106
121
/**
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
110
125
*/
111
126
public void findStronglyConnectedComponents (int v , List <List <Integer >> transposeGraph ) {
112
127
int [] vis = new int [v ];
113
128
while (!stack .isEmpty ()) {
114
- var node = stack .pop ();
129
+ int node = stack .pop ();
115
130
if (vis [node ] == 0 ) {
116
131
dfs2 (node , vis , transposeGraph );
117
132
sccsList .add (scc );
@@ -120,7 +135,12 @@ public void findStronglyConnectedComponents(int v, List<List<Integer>> transpose
120
135
}
121
136
}
122
137
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
+ */
124
144
private void dfs (int node , int [] vis , List <List <Integer >> list ) {
125
145
vis [node ] = 1 ;
126
146
for (Integer neighbour : list .get (node )) {
@@ -131,7 +151,12 @@ private void dfs(int node, int[] vis, List<List<Integer>> list) {
131
151
stack .push (node );
132
152
}
133
153
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
+ */
135
160
private void dfs2 (int node , int [] vis , List <List <Integer >> list ) {
136
161
vis [node ] = 1 ;
137
162
for (Integer neighbour : list .get (node )) {
0 commit comments