Skip to content

Commit 39df47b

Browse files
authored
Add Kosaraju Algorithm (#3859)
1 parent 54d6f79 commit 39df47b

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Stack;
6+
7+
/**
8+
* Java program that implements Kosaraju Algorithm.
9+
* @author Shivanagouda S A (https://github.com/shivu2002a)
10+
*
11+
*/
12+
13+
/**
14+
* Kosaraju algorithm is a linear time algorithm to find the strongly connected components of a
15+
directed graph, which, from here onwards will be referred by SCC. It leverages the fact that the transpose
16+
graph (same graph with all the edges reversed) has exactly the same SCCs as the original graph.
17+
18+
* A graph is said to be strongly connected if every vertex is reachable from every other vertex.
19+
The SCCs of a directed graph form a partition into subgraphs that are themselves strongly connected.
20+
Single node is always a SCC.
21+
22+
* Example:
23+
24+
0 <--- 2 -------> 3 -------- > 4 ---- > 7
25+
| ^ | ^ ^
26+
| / | \ /
27+
| / | \ /
28+
v / v \ /
29+
1 5 --> 6
30+
31+
For the above graph, the SCC list goes as follows:
32+
0, 1, 2
33+
3
34+
4, 5, 6
35+
7
36+
37+
We can also see that order of the nodes in an SCC doesn't matter since they are in cycle.
38+
39+
{@summary}
40+
* Kosaraju Algorithm:
41+
1. Perform DFS traversal of the graph. Push node to stack before returning. This gives edges sorted by lowest finish time.
42+
2. Find the transpose graph by reversing the edges.
43+
3. Pop nodes one by one from the stack and again to DFS on the modified graph.
44+
45+
The transpose graph of the above graph:
46+
0 ---> 2 <------- 3 <------- 4 <------ 7
47+
^ / ^ \ /
48+
| / | \ /
49+
| / | \ /
50+
| v | v v
51+
1 5 <--- 6
52+
53+
We can observe that this graph has the same SCC as that of original graph.
54+
55+
*/
56+
57+
public class Kosaraju {
58+
59+
// Sort edges according to lowest finish time
60+
Stack<Integer> stack = new Stack<Integer>();
61+
62+
//Store each component
63+
private List<Integer> scc = new ArrayList<>();
64+
65+
//All the strongly connected components
66+
private List<List<Integer>> sccsList = new ArrayList<>();
67+
68+
/**
69+
*
70+
* @param v Node count
71+
* @param list Adjacency list of graph
72+
* @return List of SCCs
73+
*/
74+
public List<List<Integer>> kosaraju(int v, List<List<Integer>> list){
75+
76+
sortEdgesByLowestFinishTime(v, list);
77+
78+
List<List<Integer>> transposeGraph = createTransposeMatrix(v, list);
79+
80+
findStronglyConnectedComponents(v, transposeGraph);
81+
82+
return sccsList;
83+
}
84+
85+
private void sortEdgesByLowestFinishTime(int v, List<List<Integer>> list){
86+
int vis[] = new int[v];
87+
for (int i = 0; i < v; i++) {
88+
if(vis[i] == 0){
89+
dfs(i, vis, list);
90+
}
91+
}
92+
}
93+
94+
private List<List<Integer>> createTransposeMatrix(int v, List<List<Integer>> list) {
95+
var transposeGraph = new ArrayList<List<Integer>>(v);
96+
for (int i = 0; i < v; i++) {
97+
transposeGraph.add(new ArrayList<>());
98+
}
99+
for (int i = 0; i < v; i++) {
100+
for (Integer neigh : list.get(i)) {
101+
transposeGraph.get(neigh).add(i);
102+
}
103+
}
104+
return transposeGraph;
105+
}
106+
107+
/**
108+
*
109+
* @param v Node count
110+
* @param transposeGraph Transpose of the given adjacency list
111+
*/
112+
public void findStronglyConnectedComponents(int v, List<List<Integer>> transposeGraph){
113+
int vis[] = new int[v];
114+
while (!stack.isEmpty()) {
115+
var node = stack.pop();
116+
if(vis[node] == 0){
117+
dfs2(node, vis, transposeGraph);
118+
sccsList.add(scc);
119+
scc = new ArrayList<>();
120+
}
121+
}
122+
}
123+
124+
//Dfs to store the nodes in order of lowest finish time
125+
private void dfs(int node, int vis[], List<List<Integer>> list){
126+
vis[node] = 1;
127+
for(Integer neighbour : list.get(node)){
128+
if(vis[neighbour] == 0)
129+
dfs(neighbour, vis, list);
130+
}
131+
stack.push(node);
132+
}
133+
134+
//Dfs to find all the nodes of each strongly connected component
135+
private void dfs2(int node, int vis[], List<List<Integer>> list){
136+
vis[node] = 1;
137+
for(Integer neighbour : list.get(node)){
138+
if(vis[neighbour] == 0)
139+
dfs2(neighbour, vis, list);
140+
}
141+
scc.add(node);
142+
}
143+
144+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
9+
import org.junit.jupiter.api.Test;
10+
11+
public class KosarajuTest {
12+
13+
private Kosaraju kosaraju = new Kosaraju();
14+
15+
@Test
16+
public void findStronglyConnectedComps() {
17+
//Create a adjacency list of graph
18+
var n = 8;
19+
var adjList = new ArrayList<List<Integer>>(n);
20+
21+
for (int i = 0; i < n; i++) {
22+
adjList.add(new ArrayList<>());
23+
}
24+
25+
adjList.get(0).add(1);
26+
adjList.get(1).add(2);
27+
adjList.get(2).add(0);
28+
adjList.get(2).add(3);
29+
adjList.get(3).add(4);
30+
adjList.get(4).add(5);
31+
adjList.get(4).add(7);
32+
adjList.get(5).add(6);
33+
adjList.get(6).add(4);
34+
adjList.get(6).add(7);
35+
36+
List<List<Integer>> actualResult = kosaraju.kosaraju(n, adjList);
37+
List<List<Integer>> expectedResult = new ArrayList<>();
38+
/*
39+
Expected result:
40+
0, 1, 2
41+
3
42+
5, 4, 6
43+
7
44+
*/
45+
expectedResult.add(Arrays.asList(1, 2, 0));
46+
expectedResult.add(Arrays.asList(3));
47+
expectedResult.add(Arrays.asList(5, 6, 4));
48+
expectedResult.add(Arrays.asList(7));
49+
assertTrue(expectedResult.equals(actualResult));
50+
}
51+
52+
@Test
53+
public void findStronglyConnectedCompsShouldGetSingleNodes() {
54+
//Create a adjacency list of graph
55+
var n = 8;
56+
var adjList = new ArrayList<List<Integer>>(n);
57+
58+
for (int i = 0; i < n; i++) {
59+
adjList.add(new ArrayList<>());
60+
}
61+
62+
adjList.get(0).add(1);
63+
adjList.get(1).add(2);
64+
adjList.get(2).add(3);
65+
adjList.get(3).add(4);
66+
adjList.get(4).add(5);
67+
adjList.get(5).add(6);
68+
adjList.get(6).add(7);
69+
adjList.get(7).add(0);
70+
71+
List<List<Integer>> actualResult = kosaraju.kosaraju(n, adjList);
72+
List<List<Integer>> expectedResult = new ArrayList<>();
73+
/*
74+
Expected result:
75+
0, 1, 2, 3, 4, 5, 6, 7
76+
*/
77+
expectedResult.add(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 0));
78+
assertTrue(expectedResult.equals(actualResult));
79+
}
80+
81+
}

0 commit comments

Comments
 (0)