算法快學筆記(十一):圖的深度優先搜索(DFS-Depth-First-Search)

轉載自:https://www.cnblogs.com/skywang12345/p/3711483.html

1. 介紹

圖的深度優先搜索(Depth First Search),是圖的一種搜索方法,和樹的先序遍歷比較類似。

它的思想:假設初始狀態是圖中所有頂點均未被訪問,則從某個頂點v出發,首先訪問該頂點,然後依次從它的各個未被訪問的鄰接點出發深度優先搜索遍歷圖,直至圖中所有和v有路徑相通的頂點都被訪問到。 若此時尚有其他頂點未被訪問到,則另選一個未被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到爲止。

顯然,深度優先搜索是一個遞歸的過程。

2. 原理

通過對有向圖與無向圖的遍歷過程來說明深度優先的原理

2.1 無向圖

在這裏插入圖片描述
通過深度優先的方式遍歷上圖的流程如下:

  • 第1步:訪問A。
  • 第2步:訪問(A的鄰接點)C。
    在第1步訪問A之後,接下來應該訪問的是A的鄰接點,即"C,D,F"中的一個。但在本文的實現中,頂點ABCDEFG是按照順序存儲,C在"D和F"的前面,因此,先訪問C。
  • 第3步:訪問(C的鄰接點)B。
    在第2步訪問C之後,接下來應該訪問C的鄰接點,即"B和D"中一個(A已經被訪問過,就不算在內)。而由於B在D之前,先訪問B。
  • 第4步:訪問(C的鄰接點)D。
    在第3步訪問了C的鄰接點B之後,B沒有未被訪問的鄰接點;因此,返回到訪問C的另一個鄰接點D。
  • 第5步:訪問(A的鄰接點)F。
    前面已經訪問了A,並且訪問完了"A的鄰接點B的所有鄰接點(包括遞歸的鄰接點在內)";因此,此時返回到訪問A的另一個鄰接點F。
  • 第6步:訪問(F的鄰接點)G。
  • 第7步:訪問(G的鄰接點)E。

因此訪問順序是:A -> C -> B -> D -> F -> G -> E

2.2 有向圖

在這裏插入圖片描述
通過深度優先的方式遍歷上圖的流程如下:

  • 第1步:訪問A。
  • 第2步:訪問B。
    在訪問了A之後,接下來應該訪問的是A的出邊的另一個頂點,即頂點B。
  • 第3步:訪問C。
    在訪問了B之後,接下來應該訪問的是B的出邊的另一個頂點,即頂點C,E,F。在本文實現的圖中,頂點ABCDEFG按照順序存儲,因此先訪問C。
  • 第4步:訪問E。
    接下來訪問C的出邊的另一個頂點,即頂點E。
  • 第5步:訪問D。
    接下來訪問E的出邊的另一個頂點,即頂點B,D。頂點B已經被訪問過,因此訪問頂點D。
  • 第6步:訪問F。
    接下應該回溯"訪問A的出邊的另一個頂點F"。
  • 第7步:訪問G。

因此訪問順序是:A -> B -> C -> E -> D -> F -> G

3. 實現

# -*- coding:utf-8 -*-
# @Author:sunaihua
# 深度優先算法

# 邊節點
class EdgeNode:
    def __init__(self, adjvex, weight=0):
        self.adjvex = adjvex
        self.weight = weight;

    def __str__(self):
        return '%s-%s' % (self.adjvex, self.weight)


# 頂點節點
class VertexNode:
    def __init__(self, data, adjvex, edge_list=None):
        self.adjvex = adjvex
        self.data = data
        self.edge_list = edge_list

    def __str__(self):
        edge_str = '_'.join([edge.adjvex.data for edge in self.edge_list])
        # print edge_str
        # print [edge.adjvex for edge in self.edge_list]
        return "%s-%s-(%s)" % (self.adjvex, self.data, edge_str)


class GraphAdjList:
    def __init__(self):
        self.adj_list = []

    def add_vertex(self, vertex_node):
        self.adj_list.append(vertex_node)


graph_data = {'A': ['B', 'G', 'F'], 'B': ['C', 'I', 'G', 'A'], 'C': ['D', 'I', 'B'], 'D': ['E', 'H', 'G', 'I', 'C'],
              'E': ['F', 'H', 'D'], 'F': ['A', 'G', 'E'], 'G': ['F', 'B', 'D', 'H'], 'H': ['D', 'E', 'G'],
              'I': ['B', 'C', 'D']}
visited_vertex_list = []
vertex_size = 9


# 根據數據初始化圖
def create_al_graph():
    graph_adjvex_list = GraphAdjList()
    adjvex_map = {}

    for i, data in enumerate(graph_data.iterkeys()):
        vertex_node = VertexNode(data, i)
        adjvex_map[data] = vertex_node
        graph_adjvex_list.add_vertex(vertex_node)

    for vertex_node in graph_adjvex_list.adj_list:
        adjvex_list = graph_data[vertex_node.data]
        vertex_node.edge_list = [EdgeNode(adjvex_map[adjvex]) for adjvex in adjvex_list]

    return graph_adjvex_list

# 深度優先遍歷
def dfs(adjvex):
    if len(visited_vertex_list) <= vertex_size:
        # 處理頂點信息
        if adjvex.data not in visited_vertex_list:
            visited_vertex_list.append(adjvex.data)
            print adjvex.data
        # 處理邊
        for edge in adjvex.edge_list:
            if edge.adjvex.data not in visited_vertex_list:
                visited_vertex_list.append(edge.adjvex.data)
                print edge.adjvex.data
                dfs(edge.adjvex)
    else:
        return


if __name__ == '__main__':
    graph = create_al_graph()  # 創建圖
    dfs(graph.adj_list[0])  # 從第一個節點開始遍歷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章