package com.interview.graph; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Date 10/01/2014 * @author Tushar Roy * * Given a directed graph, find all strongly connected components in this graph. * We are going to use Kosaraju's algorithm to find strongly connected component. * * Algorithm * Create a order of vertices by finish time in decreasing order. * Reverse the graph * Do a DFS on reverse graph by finish time of vertex and created strongly connected * components. * * Runtime complexity - O(V + E) * Space complexity - O(V) * * References * https://en.wikipedia.org/wiki/Strongly_connected_component * http://www.geeksforgeeks.org/strongly-connected-components/ */ public class StronglyConnectedComponent { public List<Set<Vertex<Integer>>> scc(Graph<Integer> graph) { //it holds vertices by finish time in reverse order. Deque<Vertex<Integer>> stack = new ArrayDeque<>(); //holds visited vertices for DFS. Set<Vertex<Integer>> visited = new HashSet<>(); //populate stack with vertices with vertex finishing last at the top. for (Vertex<Integer> vertex : graph.getAllVertex()) { if (visited.contains(vertex)) { continue; } DFSUtil(vertex, visited, stack); } //reverse the graph. Graph<Integer> reverseGraph = reverseGraph(graph); //Do a DFS based off vertex finish time in decreasing order on reverse graph.. visited.clear(); List<Set<Vertex<Integer>>> result = new ArrayList<>(); while (!stack.isEmpty()) { Vertex<Integer> vertex = reverseGraph.getVertex(stack.poll().getId()); if(visited.contains(vertex)){ continue; } Set<Vertex<Integer>> set = new HashSet<>(); DFSUtilForReverseGraph(vertex, visited, set); result.add(set); } return result; } private Graph<Integer> reverseGraph(Graph<Integer> graph) { Graph<Integer> reverseGraph = new Graph<>(true); for (Edge<Integer> edge : graph.getAllEdges()) { reverseGraph.addEdge(edge.getVertex2().getId(), edge.getVertex1() .getId(), edge.getWeight()); } return reverseGraph; } private void DFSUtil(Vertex<Integer> vertex, Set<Vertex<Integer>> visited, Deque<Vertex<Integer>> stack) { visited.add(vertex); for (Vertex<Integer> v : vertex.getAdjacentVertexes()) { if (visited.contains(v)) { continue; } DFSUtil(v, visited, stack); } stack.offerFirst(vertex); } private void DFSUtilForReverseGraph(Vertex<Integer> vertex, Set<Vertex<Integer>> visited, Set<Vertex<Integer>> set) { visited.add(vertex); set.add(vertex); for (Vertex<Integer> v : vertex.getAdjacentVertexes()) { if (visited.contains(v)) { continue; } DFSUtilForReverseGraph(v, visited, set); } } public static void main(String args[]){ Graph<Integer> graph = new Graph<>(true); graph.addEdge(0, 1); graph.addEdge(1, 2); graph.addEdge(2, 0); graph.addEdge(1, 3); graph.addEdge(3, 4); graph.addEdge(4, 5); graph.addEdge(5, 3); graph.addEdge(5, 6); StronglyConnectedComponent scc = new StronglyConnectedComponent(); List<Set<Vertex<Integer>>> result = scc.scc(graph); //print the result result.forEach(set -> { set.forEach(v -> System.out.print(v.getId() + " ")); System.out.println(); }); } }