using Advanced.Algorithms.DataStructures.Graph; using Advanced.Algorithms.DataStructures.Graph.AdjacencyList; using System.Collections.Generic; namespace Advanced.Algorithms.Graph { /// /// A Kosaraju Strong Connected Component Algorithm Implementation. /// public class KosarajuStronglyConnected { /// /// Returns all Connected Components using Kosaraju's Algorithm. /// public List> FindStronglyConnectedComponents(IDiGraph graph) { var visited = new HashSet(); var finishStack = new Stack(); //step one - create DFS finish visit stack foreach (var vertex in graph) { if(!visited.Contains(vertex.Value)) { kosarajuStep1(vertex, visited, finishStack); } } //reverse edges var reverseGraph = reverseEdges(graph); visited.Clear(); var result = new List>(); //now pop finish stack and gather the components while (finishStack.Count > 0) { var currentVertex = reverseGraph.GetVertex(finishStack.Pop()); if (!visited.Contains(currentVertex.Value)) { result.Add(kosarajuStep2(currentVertex, visited, finishStack, new List())); } } return result; } /// /// Just do a DFS keeping track on finish Stack of Vertices. /// private void kosarajuStep1(IDiGraphVertex currentVertex, HashSet visited, Stack finishStack) { visited.Add(currentVertex.Value); foreach(var edge in currentVertex.OutEdges) { if(!visited.Contains(edge.Value)) { kosarajuStep1(edge.Target, visited, finishStack); } } //finished visiting, so add to stack finishStack.Push(currentVertex.Value); } /// /// In step two we just add all reachable nodes to result (connected componant). /// private List kosarajuStep2(IDiGraphVertex currentVertex, HashSet visited, Stack finishStack, List result) { visited.Add(currentVertex.Value); result.Add(currentVertex.Value); foreach (var edge in currentVertex.OutEdges) { if (!visited.Contains(edge.Value)) { kosarajuStep2(edge.Target, visited, finishStack, result); } } return result; } /// /// Create a clone graph with reverse edge directions. /// private IDiGraph reverseEdges(IDiGraph graph) { var newGraph = new DiGraph(); foreach (var vertex in graph) { newGraph.AddVertex(vertex.Value); } foreach (var vertex in graph) { foreach (var edge in vertex.OutEdges) { //reverse edge newGraph.AddEdge(edge.Value, vertex.Value); } } return newGraph; } } }