轉載自: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]) # 從第一個節點開始遍歷