mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-06 17:29:31 +08:00
Add Kosaraju Algorithm (#3859)
This commit is contained in:

committed by
GitHub

parent
54d6f79acd
commit
39df47b5f2
@ -0,0 +1,144 @@
|
||||
package com.thealgorithms.datastructures.graphs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Java program that implements Kosaraju Algorithm.
|
||||
* @author Shivanagouda S A (https://github.com/shivu2002a)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Kosaraju algorithm is a linear time algorithm to find the strongly connected components of a
|
||||
directed graph, which, from here onwards will be referred by SCC. It leverages the fact that the transpose
|
||||
graph (same graph with all the edges reversed) has exactly the same SCCs as the original graph.
|
||||
|
||||
* A graph is said to be strongly connected if every vertex is reachable from every other vertex.
|
||||
The SCCs of a directed graph form a partition into subgraphs that are themselves strongly connected.
|
||||
Single node is always a SCC.
|
||||
|
||||
* Example:
|
||||
|
||||
0 <--- 2 -------> 3 -------- > 4 ---- > 7
|
||||
| ^ | ^ ^
|
||||
| / | \ /
|
||||
| / | \ /
|
||||
v / v \ /
|
||||
1 5 --> 6
|
||||
|
||||
For the above graph, the SCC list goes as follows:
|
||||
0, 1, 2
|
||||
3
|
||||
4, 5, 6
|
||||
7
|
||||
|
||||
We can also see that order of the nodes in an SCC doesn't matter since they are in cycle.
|
||||
|
||||
{@summary}
|
||||
* Kosaraju Algorithm:
|
||||
1. Perform DFS traversal of the graph. Push node to stack before returning. This gives edges sorted by lowest finish time.
|
||||
2. Find the transpose graph by reversing the edges.
|
||||
3. Pop nodes one by one from the stack and again to DFS on the modified graph.
|
||||
|
||||
The transpose graph of the above graph:
|
||||
0 ---> 2 <------- 3 <------- 4 <------ 7
|
||||
^ / ^ \ /
|
||||
| / | \ /
|
||||
| / | \ /
|
||||
| v | v v
|
||||
1 5 <--- 6
|
||||
|
||||
We can observe that this graph has the same SCC as that of original graph.
|
||||
|
||||
*/
|
||||
|
||||
public class Kosaraju {
|
||||
|
||||
// Sort edges according to lowest finish time
|
||||
Stack<Integer> stack = new Stack<Integer>();
|
||||
|
||||
//Store each component
|
||||
private List<Integer> scc = new ArrayList<>();
|
||||
|
||||
//All the strongly connected components
|
||||
private List<List<Integer>> sccsList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v Node count
|
||||
* @param list Adjacency list of graph
|
||||
* @return List of SCCs
|
||||
*/
|
||||
public List<List<Integer>> kosaraju(int v, List<List<Integer>> list){
|
||||
|
||||
sortEdgesByLowestFinishTime(v, list);
|
||||
|
||||
List<List<Integer>> transposeGraph = createTransposeMatrix(v, list);
|
||||
|
||||
findStronglyConnectedComponents(v, transposeGraph);
|
||||
|
||||
return sccsList;
|
||||
}
|
||||
|
||||
private void sortEdgesByLowestFinishTime(int v, List<List<Integer>> list){
|
||||
int vis[] = new int[v];
|
||||
for (int i = 0; i < v; i++) {
|
||||
if(vis[i] == 0){
|
||||
dfs(i, vis, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<List<Integer>> createTransposeMatrix(int v, List<List<Integer>> list) {
|
||||
var transposeGraph = new ArrayList<List<Integer>>(v);
|
||||
for (int i = 0; i < v; i++) {
|
||||
transposeGraph.add(new ArrayList<>());
|
||||
}
|
||||
for (int i = 0; i < v; i++) {
|
||||
for (Integer neigh : list.get(i)) {
|
||||
transposeGraph.get(neigh).add(i);
|
||||
}
|
||||
}
|
||||
return transposeGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v Node count
|
||||
* @param transposeGraph Transpose of the given adjacency list
|
||||
*/
|
||||
public void findStronglyConnectedComponents(int v, List<List<Integer>> transposeGraph){
|
||||
int vis[] = new int[v];
|
||||
while (!stack.isEmpty()) {
|
||||
var node = stack.pop();
|
||||
if(vis[node] == 0){
|
||||
dfs2(node, vis, transposeGraph);
|
||||
sccsList.add(scc);
|
||||
scc = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Dfs to store the nodes in order of lowest finish time
|
||||
private void dfs(int node, int vis[], List<List<Integer>> list){
|
||||
vis[node] = 1;
|
||||
for(Integer neighbour : list.get(node)){
|
||||
if(vis[neighbour] == 0)
|
||||
dfs(neighbour, vis, list);
|
||||
}
|
||||
stack.push(node);
|
||||
}
|
||||
|
||||
//Dfs to find all the nodes of each strongly connected component
|
||||
private void dfs2(int node, int vis[], List<List<Integer>> list){
|
||||
vis[node] = 1;
|
||||
for(Integer neighbour : list.get(node)){
|
||||
if(vis[neighbour] == 0)
|
||||
dfs2(neighbour, vis, list);
|
||||
}
|
||||
scc.add(node);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.thealgorithms.datastructures.graphs;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class KosarajuTest {
|
||||
|
||||
private Kosaraju kosaraju = new Kosaraju();
|
||||
|
||||
@Test
|
||||
public void findStronglyConnectedComps() {
|
||||
//Create a adjacency list of graph
|
||||
var n = 8;
|
||||
var adjList = new ArrayList<List<Integer>>(n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
adjList.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
adjList.get(0).add(1);
|
||||
adjList.get(1).add(2);
|
||||
adjList.get(2).add(0);
|
||||
adjList.get(2).add(3);
|
||||
adjList.get(3).add(4);
|
||||
adjList.get(4).add(5);
|
||||
adjList.get(4).add(7);
|
||||
adjList.get(5).add(6);
|
||||
adjList.get(6).add(4);
|
||||
adjList.get(6).add(7);
|
||||
|
||||
List<List<Integer>> actualResult = kosaraju.kosaraju(n, adjList);
|
||||
List<List<Integer>> expectedResult = new ArrayList<>();
|
||||
/*
|
||||
Expected result:
|
||||
0, 1, 2
|
||||
3
|
||||
5, 4, 6
|
||||
7
|
||||
*/
|
||||
expectedResult.add(Arrays.asList(1, 2, 0));
|
||||
expectedResult.add(Arrays.asList(3));
|
||||
expectedResult.add(Arrays.asList(5, 6, 4));
|
||||
expectedResult.add(Arrays.asList(7));
|
||||
assertTrue(expectedResult.equals(actualResult));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findStronglyConnectedCompsShouldGetSingleNodes() {
|
||||
//Create a adjacency list of graph
|
||||
var n = 8;
|
||||
var adjList = new ArrayList<List<Integer>>(n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
adjList.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
adjList.get(0).add(1);
|
||||
adjList.get(1).add(2);
|
||||
adjList.get(2).add(3);
|
||||
adjList.get(3).add(4);
|
||||
adjList.get(4).add(5);
|
||||
adjList.get(5).add(6);
|
||||
adjList.get(6).add(7);
|
||||
adjList.get(7).add(0);
|
||||
|
||||
List<List<Integer>> actualResult = kosaraju.kosaraju(n, adjList);
|
||||
List<List<Integer>> expectedResult = new ArrayList<>();
|
||||
/*
|
||||
Expected result:
|
||||
0, 1, 2, 3, 4, 5, 6, 7
|
||||
*/
|
||||
expectedResult.add(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 0));
|
||||
assertTrue(expectedResult.equals(actualResult));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user