Repository: TheAlgorithms/Java
Pull request #3859 (2023-01-17 02:49:13)

Adding Kosaraju Algorithm
<!-- For completed items, change [ ] to [x] -->

- [ x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [ x] This pull request is all my own work -- I have not plagiarized it.
- [ x] All filenames are in PascalCase.
- [ x] All functions and variable names follow Java naming conventions.
- [ ] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.


shivu2002a: Hi, @siriak, I've added test cases also.
shivu2002a: @siriak Suggested changes have been implemented.
shivu2002a: @siriak Done!!

Patch:
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java b/src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java
new file mode 100644
index 00000000..b3632b47
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java
@@ -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);
+    }
+    
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java
new file mode 100644
index 00000000..5395b04e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java
@@ -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));
+    }
+
+}