欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图的深度优先搜索

程序员文章站 2022-06-11 11:10:21
...

深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件)。在一个HTML文件中,当一个超链被选择后,被链接的HTML文件将执行深度优先搜索,即在搜索其余的超链结果之前必须先完整地搜索单独的一条链。深度优先搜索沿着HTML文件上的超链走到不能再深入为止,然后返回到某一个HTML文件,再继续选择该HTML文件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。

(一)基本思想

深度优先遍历图的方法是,从图中某顶点v出发:
1 访问顶点v;
2 依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
3 若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

(二)代码实现

有一个图如下,求深度优先搜索顺序。

图的深度优先搜索

分析:首先看看每个元素和哪些元素相邻

元素 相邻元素
1 2,3
2 1,4,5
3 1,6,7
4 2,8
5 2,8
6 3,7
7 3,6
8 4,5

(1)假设从节点1开始遍历(事实上可以从任何一个节点开始),与1相邻的是2和3
(2)遍历2之后,进入递归。2有三个相邻元素,1,4,5。因为1已经遍历过了,因此遍历4
(3)遍历4之后,进入递归。与4相邻的是2和8,因为2已经遍历过了,所以遍历8
(4)遍历8之后,进入递归。与8相邻的是4和5,因为4已经遍历过了,所以遍历5
(5)遍历5之后,进入递归。与5相邻的是2和8,因为2和8都已经遍历过了,所以递归终止。返回步骤(4)
(6)因为步骤(4)中的4和5都已经遍历过了,返回步骤(3)
(7)因为步骤(3)中的2和8都已经遍历过了,返回步骤(2)
(8)因为步骤(2)中的1,4,5都已经遍历过了,返回步骤(1)
(9)因为步骤(1)中的2已经遍历过了,这次遍历的是3
(10)遍历3之后,进入递归。与3相邻的是6和7,所以遍历6
(11)遍历6之后,进入递归。与6相邻的是3和7,因为3已经遍历过了,所以遍历7
(12)遍历7之后,进入递归。与7相邻的是3和6,因为3和6都已经遍历过了,递归结束。返回步骤(11)
(13)在(11)中,3和7都遍历过了,返回步骤(10)
(14)在(10)中,6和7都遍历过,返回步骤(1)
(15)在步骤(1)中,没有未遍历过的元素。遍历结束。
由上面的15个步骤可知,深度搜索遍历的顺序为:1,2,4,8,5,3,6,7。

下面是代码实现:

#!/usr/bin/python
# -*- coding: utf-8 -*-

class Graph(object):

    def __init__(self,*args,**kwargs):
        self.node_neighbors = {}
        self.visited = {}

    def add_nodes(self,nodelist):

        for node in nodelist:
            self.add_node(node)

    def add_node(self,node):
        if not node in self.nodes():
            self.node_neighbors[node] = []

    def add_edge(self,edge):
        u,v = edge
        if(v not in self.node_neighbors[u]) and ( u not in self.node_neighbors[v]):
            self.node_neighbors[u].append(v)

            if(u!=v):
                self.node_neighbors[v].append(u)

    def nodes(self):
        return self.node_neighbors.keys()

    def depth_first_search(self,root=None):
        order = []
        def dfs(node):
            self.visited[node] = True
            order.append(node)
            for n in self.node_neighbors[node]:
                if not n in self.visited:
                    dfs(n)

        if root in self.nodes():
            dfs(root)

        for node in self.nodes():
            if not node in self.visited:
                dfs(node)

        return order


if __name__ == '__main__':
    g = Graph()
g.add_nodes([i+1 for i in range(8)])
g.add_edge((1, 2))
g.add_edge((1, 3))
g.add_edge((2, 4))
g.add_edge((2, 5))
g.add_edge((4, 8))
g.add_edge((5, 8))
g.add_edge((3, 6))
g.add_edge((3, 7))
g.add_edge((6, 7))
print "Original nodes: ", g.nodes()

order = g.depth_first_search(1)
print "Depth-First-Search order: ", order

运行结果:

Original nodes: [1, 2, 3, 4, 5, 6, 7, 8]
Depth-First-Search order: [1, 2, 4, 8, 5, 3, 6, 7]