2011-07-10 7 views
29

ここでは、Tarjanのサイクル検出を実装しています。アルゴリズムは、ここで発見された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

なぜv.lowlink = Math.Min(v.lowlink、w.lowlink)以外の 'v.lowlink = Math.Min(v.lowlink、w.index)'ですか? –

+0

@LinMaいずれか技術的に正しいです。 –

答えて

9

上記は実際には正しいですが、私は強く結びついた要素が何であるか分かりませんでした。私は強く接続されたコンポーネントの空のListを返す関数を期待していましたが、単一のノードのリストを返していました。

私は上記が働いていると信じています。必要ならば自由に使用してください!

+0

質問:DetectCycle関数に渡されるDepGraphを構築するときに、サイクルに入ることはありませんか?あなたのように思えますし、そうした場合、その時のサイクルを検出していませんか? – Joe

+5

こんにちは、上記の有用な発見し、他の確立されたソリューションを見つけることができませんでしたので、他の人が発見して貢献するためにgithubにそれを叩いただけです:https://github.com/danielrbradley/CycleDetection – danielrbradley

+0

作業が確認されました。私は少し違ったことに、頂点自体に副作用を強制したくないので(本質的にVertexでインデックスとロー値の辞書を作っています)、これは本当にうまくいっています。ありがとうございました! – user420667

3

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()) 
+0

ここにquickgraphへのリンクがあります:http://quickgraph.codeplex.com/ – devinbost

2

例は、誰もがすぐにそれを再生したいはずです機能ではありません。また、それはスタックベースであることに注意してください。これは、グラフの中で最も些細なものを与えるだけでスタックを爆発させます。ここでは、グラフはTarjanのウィキペディアのページに表示モデルユニットテストでの作業の例である:行われているかを確認するのは簡単ですので、私は頂点オブジェクトへのidプロパティを追加

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

が、それはにISN厳密に必要とされる。私はまたコードのいくつかを少しきれいにしました、著者はページの擬似コードからの命名を使用していましたが、それは比較には良いですが、あまり有益ではありませんでした。

+0

答えは無作為に並べ替えるので、「上」は意味がありません。特定の回答をユーザーの名前またはリンク(「共有」から)で参照する方が効果的です。 – Mogsdad

+0

私は2つのノードを追加しています。最初のノードはもう一方のノードに接続されています。この結果は、各ノードを1つずつ含む2つの「ループ」です。これはゼロループであってはなりませんか?編集:nevermind( "有向サイクル上にない頂点は単独で強く連結されたコンポーネントを形成します。たとえば、度数が0または外数が0の頂点、または非循環グラフの頂点などです。) –

関連する問題