2009-03-07 22 views
6

馬の系図データを再帰的にロードしています。 いくつかの間違ったデータセットに対して、私の再帰は決して止まらない...それはデータにサイクルがあるからです。深さ優先探索中の系図のサイクルを検出する

繰り返しを停止するようにこれらのサイクルを検出するにはどうすればよいですか?

私は、すべての「訪問済み」馬のhashTableを定期的に維持していると考えました。 しかし、それは馬が木の中で2回あることがあるので、いくつかの偽陽性を見つけるでしょう。

馬は、ITSELFの祖父または祖父または曾祖父として現れることはありません。

+1

バイナリツリーにはサイクルというものはありません。正しい家系図データでさえ、バイナリツリーではありません。私は質問を編集して "グラフ" – Triptych

+0

が好奇心をそそりました。これは、(サーブブレッドのように)投与量指数、Werk Nick Ratingか何かを調べるためのものですか? – nlucaroni

+0

いいえ...私は馬の血統全体をファイルにエクスポートしています。私は近親交配を検出するためにも使用しますが、私のソフトウェア製品は特定の品種ではないため、私は分析する歴史的データはあまりありません。 – Romias

答えて

6

擬似コード:

void ProcessTree(GenTreeNode currentNode, Stack<GenTreeNode> seen) 
{ 
    if(seen.Contains(currentNode)) return; 
    // Or, do whatever needs to be done when a cycle is detected 

    ProcessHorse(currentNode.Horse); // Or whatever processing you need 

    seen.Push(currentNode); 

    foreach(GenTreeNode childNode in currentNode.Nodes) 
    { 
     ProcessTree(childNode, seen); 
    } 

    seen.Pop(); 
} 

基本的な考え方は、我々はすでにダウンし、現在のノードへ行く途中に見てきたすべてのノードのリストを維持することです。既に完了したノードに戻った場合は、サイクルが形成されていることがわかります(値をスキップするか、実行する必要があるものはすべて実行してください)。

+0

それはうまくいくようです...私の指でうぬぼれた:)私はそれを試してみましょう、いくつかの国境のケースがないと思う。私はあなたに知らせるでしょう:) – Romias

+0

まあ...これは魅力のように働いた。とにかく私のテスト系図データは実際にはジャンクではありましたが、少なくとも私のソフトウェアはそれを許容しています。私はまた、スタックの長さに関連する別のストップ条件を追加しました...ツリーの最大深度を設定します。ありがとう! – Romias

+0

@Romias:問題ありません:] –

2

ツリーのルートに至るすべての要素のスタックを維持します。

ツリーを下るたびに、スタックで子要素をスキャンします。一致するものが見つかった場合は、ループを発見してその子をスキップする必要があります。それ以外の場合は、子をスタックに押し込み、処理を続行します。ツリーをバックトラックするたびに、要素をスタックからポップして破棄します。

(系図のデータの場合には、ツリー内の「子」ノードは、おそらく「親」ノードの生物学的な親である。)

1

これを検出するための非常に簡単な方法は、その制約をチェックすることです自分自身:

馬は、ITSELFの父または祖父またはgreatgrandfatherとして表示されることはできません。

ノードをノードに挿入するときは、ツリーをルートにトラバースして、馬がどのような種類の親としても存在しないことを確認します。

これを高速化するために、各ノードにハッシュテーブルを関連付けて、そのようなルックアップの回答をキャッシュすることができます。次に、そのノードの下に馬を挿入したときに、パス全体を検索する必要はありません。

0

ハッシュテーブルの解決策は、あなたは馬の代わりにノードを追跡します。値/馬が前のノードの値/馬と同じであっても、新しい馬を読むたびに必ず新しいノードを作成するようにしてください。

0

あなたはツリーではなくdirected acyclic graphを扱っています。馬の子孫もその祖先になることができないので、サイクルがあってはいけません。

これを知っていると、有向非循環グラフに固有のコード技法を適用する必要があります。

+0

馬を持っていると、馬に2つの親があるので、常にバイナリツリーを取得します。これがうまく形成されないときは時々あなたはサイクルを取得します。 – Romias

+0

交配により、これはバイナリツリーではなくDAGになります。同様に、コート・ビジョン(http://www.pedigreequery.com/court+vision)には、ネイティブ・ダンサー4x5とナスララ5x5があります。ここではバイナリツリーとして示していますが、実際にはDAGです。 – nlucaroni

+0

ええ...あなたは正しいです...私は、同系の馬であり、血統の中での彼らのポジションであるとして、近親交配の場合は考慮していませんでした。 – Romias

2

これは、インタビューのトリビア質問を最終的に適用できるケースのように聞こえます.O(1)メモリだけを使用してリンクされたリストでサイクルを見つけることができます。

この場合、リンクされたリストは列挙する要素のシーケンスです。2つの列挙子を使用し、1つは半分の速度で実行し、速いものが遅いものに実行される場合は、ループがあります。また、これはO(n^2)時間の代わりにO(n)時間になります。欠点は、ノードのいくつかが複数回処理された後のループについてだけ見つけ出すことです。

この例では、「半分の速度」の方法を、より簡単に書ける「ドロップマーカー」方法に置き換えました。

class GenTreeNode { 
    ... 

    ///<summary>Wraps an the enumeration of linked data structures such as trees and linked lists with a check for cycles.</summary> 
    private static IEnumerable<T> CheckedEnumerable<T>(IEnumerable<T> sub_enumerable) { 
     long cur_track_count = 0; 
     long high_track_count = 1; 
     T post = default(T); 
     foreach (var e in sub_enumerable) { 
      yield return e; 
      if (++cur_track_count >= high_track_count) { 
       post = e; 
       high_track_count *= 2; 
       cur_track_count = 0; 
      } else if (object.ReferenceEquals(e, post)) { 
       throw new Exception("Infinite Loop"); 
      } 
     } 
    } 

    ... 

    ///<summary>Enumerates the tree's nodes, assuming no cycles</summary> 
    private IEnumerable<GenTreeNode> tree_nodes_unchecked() { 
     yield return this; 
     foreach (var child in this.nodes) 
      foreach (var e in child.tree_nodes_unchecked()) 
       yield return e; 
    } 
    ///<summary>Enumerates the tree's nodes, checking for cycles</summary> 
    public IEnumerable<GenTreeNode> tree_nodes() 
    { 
     return CheckedEnumerable(tree_nodes_unchecked()); 
    } 

    ... 

    void ProcessTree() { 
     foreach (var node in tree_nodes()) 
      proceess(node); 
    } 
} 
+0

今のところ... "見た"リストの解決策が働いています。私はあなたのアプローチがより効率的でなければならないことを認識しています。私は父から児童への奉仕のためにいくつかの木を持っており、私はあなたのアプローチを使うことができます。とにかくありがとう。 – Romias