算法快学笔记(十一):图的深度优先搜索(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])  # 从第一个节点开始遍历

猜你喜欢

转载自blog.csdn.net/sun7545526/article/details/88351699