web-dev-qa-db-ja.com

Python幅優先検索の実装

オンラインで例を見つけましたが、BFS要素のシーケンスのみを返すだけでは計算には不十分です。ルートがBFSツリーの最初のレベルであり、その子が2番目のレベルなどであるとしましょう。以下のコードから、各ノードの親と各ノードの親をどのように知ることができますか(オブジェクトを作成しますその親とツリーレベルを保存します)?

# sample graph implemented as a dictionary
graph = {'A': ['B', 'C', 'E'],
         'B': ['A','D', 'E'],
         'C': ['A', 'F', 'G'],
         'D': ['B'],
         'E': ['A', 'B','D'],
         'F': ['C'],
         'G': ['C']}

# visits all the nodes of a graph (connected component) using BFS
def bfs_connected_component(graph, start):
   # keep track of all visited nodes
   explored = []
   # keep track of nodes to be checked
   queue = [start]

   # keep looping until there are nodes still to be checked
   while queue:
       # pop shallowest node (first node) from queue
       node = queue.pop(0)
       if node not in explored:
           # add node to list of checked nodes
           explored.append(node)
           neighbours = graph[node]

           # add neighbours of node to queue
           for neighbour in neighbours:
               queue.append(neighbour)
   return explored

bfs_connected_component(graph,'A') # returns ['A', 'B', 'C', 'E', 'D', 'F', 'G']
7
user5575144

最初にレベル0を開始ノードに割り当てることにより、各ノードのレベルを追跡できます。次に、ノードの各ネイバーに対してX assign level level_of_X + 1

また、コードは同じノードをキューに複数回プッシュします。それを避けるために、別のリストvisitedを使用しました。

# sample graph implemented as a dictionary
graph = {'A': ['B', 'C', 'E'],
         'B': ['A','D', 'E'],
         'C': ['A', 'F', 'G'],
         'D': ['B'],
         'E': ['A', 'B','D'],
         'F': ['C'],
         'G': ['C']}


# visits all the nodes of a graph (connected component) using BFS
def bfs_connected_component(graph, start):
    # keep track of all visited nodes
    explored = []
    # keep track of nodes to be checked
    queue = [start]

    levels = {}         # this dict keeps track of levels
    levels[start]= 0    # depth of start node is 0

    visited= [start]     # to avoid inserting the same node twice into the queue

    # keep looping until there are nodes still to be checked
    while queue:
       # pop shallowest node (first node) from queue
        node = queue.pop(0)
        explored.append(node)
        neighbours = graph[node]

        # add neighbours of node to queue
        for neighbour in neighbours:
            if neighbour not in visited:
                queue.append(neighbour)
                visited.append(neighbour)

                levels[neighbour]= levels[node]+1
                # print(neighbour, ">>", levels[neighbour])

    print(levels)

    return explored

ans = bfs_connected_component(graph,'A') # returns ['A', 'B', 'C', 'E', 'D', 'F', 'G']
print(ans)
8
Anonta

ええ、このコードは幅優先の方法でのみノードにアクセスします。これはそれ自体で多くのアプリケーションで行うのに便利です(たとえば、重みのないグラフで最短パスを見つける)

実際にBFSツリーを返すには、追加の作業が必要になります。各ノードの子のリストを保存するか、(node、parent-node)のペアを返すことを考えることができます。どちらの表現でも、ツリーの構造を把握できるはずです。

ここで注意すべきもう1つのことは、コードがpythonリストをキューとして使用することです。これはお勧めできません。リストから最初の要素を削除するには、O(n)時間。

2
Shalan