-
Notifications
You must be signed in to change notification settings - Fork 296
Expand file tree
/
Copy pathKosarajuStronglyConnected.cs
More file actions
118 lines (100 loc) · 3.48 KB
/
KosarajuStronglyConnected.cs
File metadata and controls
118 lines (100 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using Advanced.Algorithms.DataStructures.Graph;
using Advanced.Algorithms.DataStructures.Graph.AdjacencyList;
using System.Collections.Generic;
namespace Advanced.Algorithms.Graph
{
/// <summary>
/// A Kosaraju Strong Connected Component Algorithm Implementation.
/// </summary>
public class KosarajuStronglyConnected<T>
{
/// <summary>
/// Returns all Connected Components using Kosaraju's Algorithm.
/// </summary>
public List<List<T>>
FindStronglyConnectedComponents(IDiGraph<T> graph)
{
var visited = new HashSet<T>();
var finishStack = new Stack<T>();
//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<List<T>>();
//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<T>()));
}
}
return result;
}
/// <summary>
/// Just do a DFS keeping track on finish Stack of Vertices.
/// </summary>
private void kosarajuStep1(IDiGraphVertex<T> currentVertex,
HashSet<T> visited,
Stack<T> 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);
}
/// <summary>
/// In step two we just add all reachable nodes to result (connected componant).
/// </summary>
private List<T> kosarajuStep2(IDiGraphVertex<T> currentVertex,
HashSet<T> visited, Stack<T> finishStack,
List<T> 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;
}
/// <summary>
/// Create a clone graph with reverse edge directions.
/// </summary>
private IDiGraph<T> reverseEdges(IDiGraph<T> graph)
{
var newGraph = new DiGraph<T>();
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;
}
}
}