这是tarjan循环检测的一个有效的C#实现。
该算法可在此处找到: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
public class TarjanCycleDetect
{
private static List<List<Vertex>> StronglyConnectedComponents;
private static Stack<Vertex> S;
private static int index;
private static DepGraph dg;
public static List<List<Vertex>> DetectCycle(DepGraph g)
{
StronglyConnectedComponents = new List<List<Vertex>>();
index = 0;
S = new Stack<Vertex>();
dg = g;
foreach (Vertex v in g.vertices)
{
if (v.index < 0)
{
strongconnect(v);
}
}
return StronglyConnectedComponents;
}
private static void strongconnect(Vertex v)
{
v.index = index;
v.lowlink = index;
index++;
S.Push(v);
foreach (Vertex w in v.dependencies)
{
if (w.index < 0)
{
strongconnect(w);
v.lowlink = Math.Min(v.lowlink, w.lowlink);
}
else if (S.Contains(w))
{
v.lowlink = Math.Min(v.lowlink, w.index);
}
}
if (v.lowlink == v.index)
{
List<Vertex> scc = new List<Vertex>();
Vertex w;
do
{
w = S.Pop();
scc.Add(w);
} while (v != w);
StronglyConnectedComponents.Add(scc);
}
}
注意DepGraph只是一个Vertex列表。和Vertex有一个代表边缘的其他顶点列表。索引和低链接也被初始化为-1
编辑:这是有效的......我只是误解了结果。
答案 0 :(得分:9)
以上实际上是正确的,我不明白强连接组件是什么。我期待该函数返回一个空连接的强连接组件列表,但它返回了一个单节点列表。
我相信以上是有效的。如果需要,请随意使用!
答案 1 :(得分:4)
截至2008年,quickgraph已经支持此算法。有关实现的信息,请参阅StronglyConnectedComponentsAlgorithm
类;有关使用情况快捷方式,请参阅AlgorithmExtensions.StronglyConnectedComponents
方法。
示例:
// Initialize result dictionary
IDictionary<string, int> comps = new Dictionary<string, int>();
// Run the algorithm
graph.StronglyConnectedComponents(out comps);
// Group and filter the dictionary
var cycles = comps
.GroupBy(x => x.Value, x => x.Key)
.Where(x => x.Count() > 1)
.Select(x => x.ToList())
答案 2 :(得分:4)
如果有人想要快速使用它,上面提到的示例是不起作用的。另请注意,它是基于堆栈的,如果您提供除最简单的图形之外的任何内容,它将引爆您的堆栈。下面是一个工作示例,其中包含对Tarjan维基百科页面上显示的图形进行建模的单元测试:
public class Vertex
{
public int Id { get;set; }
public int Index { get; set; }
public int Lowlink { get; set; }
public HashSet<Vertex> Dependencies { get; set; }
public Vertex()
{
Id = -1;
Index = -1;
Lowlink = -1;
Dependencies = new HashSet<Vertex>();
}
public override string ToString()
{
return string.Format("Vertex Id {0}", Id);
}
public override int GetHashCode()
{
return Id;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Vertex other = obj as Vertex;
if (other == null)
return false;
return Id == other.Id;
}
}
public class TarjanCycleDetectStack
{
protected List<List<Vertex>> _StronglyConnectedComponents;
protected Stack<Vertex> _Stack;
protected int _Index;
public List<List<Vertex>> DetectCycle(List<Vertex> graph_nodes)
{
_StronglyConnectedComponents = new List<List<Vertex>>();
_Index = 0;
_Stack = new Stack<Vertex>();
foreach (Vertex v in graph_nodes)
{
if (v.Index < 0)
{
StronglyConnect(v);
}
}
return _StronglyConnectedComponents;
}
private void StronglyConnect(Vertex v)
{
v.Index = _Index;
v.Lowlink = _Index;
_Index++;
_Stack.Push(v);
foreach (Vertex w in v.Dependencies)
{
if (w.Index < 0)
{
StronglyConnect(w);
v.Lowlink = Math.Min(v.Lowlink, w.Lowlink);
}
else if (_Stack.Contains(w))
{
v.Lowlink = Math.Min(v.Lowlink, w.Index);
}
}
if (v.Lowlink == v.Index)
{
List<Vertex> cycle = new List<Vertex>();
Vertex w;
do
{
w = _Stack.Pop();
cycle.Add(w);
} while (v != w);
_StronglyConnectedComponents.Add(cycle);
}
}
}
[TestMethod()]
public void TarjanStackTest()
{
// tests simple model presented on https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
var graph_nodes = new List<Vertex>();
var v1 = new Vertex() { Id = 1 };
var v2 = new Vertex() { Id = 2 };
var v3 = new Vertex() { Id = 3 };
var v4 = new Vertex() { Id = 4 };
var v5 = new Vertex() { Id = 5 };
var v6 = new Vertex() { Id = 6 };
var v7 = new Vertex() { Id = 7 };
var v8 = new Vertex() { Id = 8 };
v1.Dependencies.Add(v2);
v2.Dependencies.Add(v3);
v3.Dependencies.Add(v1);
v4.Dependencies.Add(v3);
v4.Dependencies.Add(v5);
v5.Dependencies.Add(v4);
v5.Dependencies.Add(v6);
v6.Dependencies.Add(v3);
v6.Dependencies.Add(v7);
v7.Dependencies.Add(v6);
v8.Dependencies.Add(v7);
v8.Dependencies.Add(v5);
v8.Dependencies.Add(v8);
graph_nodes.Add(v1);
graph_nodes.Add(v2);
graph_nodes.Add(v3);
graph_nodes.Add(v4);
graph_nodes.Add(v5);
graph_nodes.Add(v6);
graph_nodes.Add(v7);
graph_nodes.Add(v8);
var tcd = new TarjanCycleDetectStack();
var cycle_list = tcd.DetectCycle(graph_nodes);
Assert.IsTrue(cycle_list.Count == 4);
}
我在Vertex对象中添加了一个Id属性,因此很容易看到正在做什么,并不是严格需要的。我还清理了一些代码,作者正在使用页面伪代码命名,这对比较有好处,但它的信息量不大。