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;
}
}
}