2017-11-15 12 views
1

最近、私はウェブサイト(https://brilliant.org/wiki/depth-first-search-dfs/)でデプスファーストサーチのコードを探していました。しかし、彼らの実装はcompletly correct.Thisではありませんあなたが見ることができるように、彼らはデプスファーストサーチインプリメンテーションの出力が正しくない

def depth_first_search(graph): 
    visited, stack = set(), [root] 
    while stack: 
     vertex = stack.pop() 
     if vertex not in visited: 
      visited.add(vertex) 
      stack.extend(graph[vertex] - visited) 
    return visited 

投稿をコードで、それらが適用ロジックが正しいですが、彼らは毎回プログラムの実行を出力を変更する設定操作を使用していました。

これは私の完全なプログラムである

graph = {'A': {'B', 'S'}, 'B': {'A'}, 'C': {'S', 'F', 'D', 'E'}, 
    'D': {'C'}, 'E': {'H', 'C'}, 'F': {'C', 'G'}, 'G': {'S', 'F', 'H'}, 
    'H': {'G', 'E'}, 'S': {'A', 'G', 'C'}} 

def depth_first_search(graph, root): 
    visited, stack = set(), [root] 
    while stack: 
     vertex = stack.pop() 
     if vertex not in visited: 
      visited.add(vertex) 
      stack.extend(graph[vertex] - visited) 
    return visited 

print(depth_first_search(graph, 'A')) 

以下は、私がプログラムを実行evertime私が手に出力がある

{'H', 'C', 'B', 'A', 'D', 'S', 'F', 'E', 'G'} 
{'D', 'E', 'C', 'H', 'G', 'S', 'A', 'B', 'F'} 
{'G', 'F', 'C', 'H', 'E', 'D', 'B', 'S', 'A'} and so on.... 

設定した理由は、特に我々のようにコードの下の行のために理にかなっています未探索の頂点だけをスタックに格納するようにします。

ように設定差分演算は、私はセットを使用して回避し、リスト

graph = {'A': ['B', 'S'], 'B': ['A'], 'C': ['S', 'F', 'D', 'E'], 
'D': ['C'], 'E': ['H', 'C'], 'F': ['C', 'G'], 'G': ['S', 'F', 'H'], 
    'H': ['G', 'E'], 'S': ['A', 'G', 'C']} 

def depth_first_search(graph, root): 
    visited, stack = [], [root] 
    while stack: 
     vertex = stack.pop() 
     if vertex not in visited: 
      visited.append(vertex) 
      neighbours = graph[vertex] 
      for neighbour in neighbours: 
       # ensures we only add unexplored nodes to the stack 
       if neighbour not in visited: 
        stack.append(neighbour) 
    return visited 

print(depth_first_search(graph, 'A')) 

をどう作るために、コードを少し微調整above.So述べたように、それはコストがかかりますobjective.Butことを達成するが実行

stack.extend(graph[vertex] - visited) 

私は、正しい結果が

でなければなりません

['A', 'S', 'C', 'E', 'H', 'G', 'F', 'D', 'B'] 

間違った結果を取得します10

私は間違っていますか?

答えて

2

あなたが得ている答えは、そのグラフの有効なDFS順序です。ノードの隣人がアルファベット順に横断されなければならないという書かれていない制限があるようです。これを念頭に置いて、2つのことを考えてみましょう。

まず、定義されている順序でノードのネイバーをスタックに追加します。しかし、あなたがpop()をスタックから外したときは、最後のアイテムを最初にスタックから外してください。つまり、ノードを逆順に選択しています。それはあなたが隣人を反復する順序を逆にすることによって解決することは簡単です:

for neighbour in reversed(neighbours): 

第二には、あなたが実際にアルファベット順ににノードの隣人を定義していません。あなたのいずれかの定義での値をアルファベット順、または反復前にそれらをソートする必要があります。

for neighbour in reversed(sorted(neighbours)): 
# or 
for neighbour in sorted(neighbours, reverse=True): 
+0

もう一度お世話になりました。しかし、私は1つの質問があります。本当にグラフの値をアルファベット化する必要がありますか?私がグラフを見れば、ノードが他のノードに接続されている単純な無向グラフです。なぜ私がアルファベットを並べるかどうかは重要ですか?とにかく接続は同じになるでしょうか?私が間違っていたら私を修正してください。 –

+0

与えられたグラフのDFS順序は1つではありません。バックアップを取って別のパスをたどる前に、あるチェーンを最後まで追跡する限り、どのステップで最初に訪問したかは実際には関係ありません。これは、さまざまな方法で行うことができます。つまり、すべて異なる(有効な)注文になります。あなたは単一の標準的な検索順序を探しているようで、その結果はアルファベット順にノードを訪問することで得ることができるので、あなたが探していたものと仮定しました。 – glibdud

+0

ああ私が見ているのはちょうど私が探していたものです。私は、DFSはアルファベット順にトラバースされることを意図していると思っていました。 –

1

それはあなたが持っている最初のコードサンプルは、トポロジカルソートを生成するために意図されていないように見えますが、単純にすべて一覧表示しますルートから到達できるノード。おそらくそれが間違っているわけではないことに注意することが重要です、それはちょうどあなたに命令を与えることになっていません。

あなたのコードは基本的にそれがすべきことを言います。あなたが得ている出力はあなたが期待しているものと同じです。限り、DFSが必要なだけです。

vertex = stack.pop()を呼び出すと、最後の(つまり一番右の要素)が返されることを忘れています。stack.append(neighbour)に電話すると、子をスタックにプッシュしています左から順に

"左端"分岐を最初に通過するDFSを必要とする場合、それらをスタックに追加する前に、隣接/子の順序を逆にする必要があります。

EDIT:私は自由にコメントするのに十分な担当者がいませんが、私の答えは基本的にglibdud'sと同じです。あなたが走っている問題は、基本的なDFSの一部ではないあなたの頭に追加の制限を適用しているようです。

+0

あなたは正しいです!実際私の考え方では、要素をスタックにプッシュするが、LIFOルールに基本的に従う最後のプッシュされた要素だけをポップするDFSで必要な基本スタック操作を行っていました。 –

関連する問題