图的深度和广度优先搜索

        图的遍历有深度优先搜索和广度优先搜索两种

        深度优先搜索

       类似于树的先根遍历,但图不同于树的地方在于,它可能存在回路/环,那么在进行遍历的时候,同一个顶点可能会被多次搜索到,如果一个顶点被访问过了,要进行标记,当它再次被搜索到,不再对其进行访问。图的深度优先遍历的过程是,任意选定一个顶点,访问它,然后依次对它的邻接顶点进行深度优先遍历,这是一个递归的过程,通过深度优先访问到的顶点都是第一个选定的顶点能够到达的顶点,但图有可能不是联通的,所以当选定一个顶点进行深度优先遍历的时候,不一定能够把所有的顶点都给搜索到,因此有可能需要进行多次深度优先遍历。通过上面的叙述,我们需要1)设定一个visited向量来标记顶点是否被访问过,2)给出一个方法计算指定顶点的邻接点 3)确保所有的顶点被访问到,可能要多次执行深度优先遍历操作。这里还要说一下计算顶点的邻接点,对于无向图来说没什么,但对于有向图,一个顶点的邻接点取顶点邻接到的顶点序列还是取顶点邻接到的顶点序列加上邻接自的顶点序列,取决于实现,都可以。

        广度优先搜索

        类似于树的层次遍历,同样需要标记顶点,避免已经访问过的顶点再次被访问。层次遍历的逻辑很简单,只要借助于一个辅助队列进行。

       下面给出一个代码实现对下图的遍历,图的存储表示采用邻接表形式,其他存储表示的图的遍历逻辑也差不多,就不一一实现了。

 

from collections import deque
class Vertex:
    def __init__(self, data = None):
        self.data = data
        self.in_arcs = []
        self.out_arcs = []

    def set_in_arc(self, v):
        self.in_arcs.append(v)

    def set_out_arc(self, v):
        self.out_arcs.append(v)

    def __str__(self):
        return str(self.data)

class Graph:
    def __init__(self, vertexs = None):
        self.vertexs = [i for i in vertexs] if vertexs else []
    
    def insert_vertex(self, vertex):
        self.vertexs.append(vertex)

    def set_in_arc(self, i, j):
        vertex = self.vertexs[i]
        vertex.set_in_arc(j)

    def set_out_arc(self, i, j):
        vertex = self.vertexs[i]
        vertex.set_out_arc(j)

    def set_out_arcs(self, i, arcs):
        for j in arcs:
            self.set_out_arc(i, j)

    def set_in_arcs(self):
        for i, v in enumerate(self.vertexs):
            for j in v.out_arcs:
                self.vertexs[j].set_in_arc(i)

    def get_in_arcs(self, i):
        return [(j, i) for j in self.vertexs[i].in_arcs]

    def get_out_arcs(self, i):
        return [(i, j) for j in self.vertexs[i].out_arcs]

    def dfstraverse(self):
        vertexs = self.vertexs
        visited = [0] * len(vertexs)
        def dfs(i):
            nonlocal visited
            visited[i] = 1
            yield vertexs[i]
            for _, j in self.get_out_arcs(i):
                if not visited[j]:
                    yield from dfs(j)
        for i in range(len(vertexs)):
            if not visited[i]:
                yield from dfs(i)

    def bfstraverse(self):
        q = deque()
        vertexs = self.vertexs
        visited = [0] * len(vertexs)
        for i in range(len(vertexs)): 
            if not visited[i]:
                yield vertexs[i]
                visited[i] = 1
                q.append(i)
                while q:
                    j = q.popleft()
                    for _, k in self.get_out_arcs(j):
                        if not visited[k]:
                            yield vertexs[k]
                            visited[k] = 1
                            q.append(k)


g = Graph()
_ = [g.insert_vertex(Vertex(i)) for i in "A B C D E F G H I J K L M".split()]
g.set_out_arcs(0, (11, 5, 2, 1))
g.set_out_arcs(1, (12, 0))
g.set_out_arcs(2, (0,))
g.set_out_arcs(3, (4,))
g.set_out_arcs(4, (3,))
g.set_out_arcs(5, (0,))
g.set_out_arcs(6, (10, 8, 7))
g.set_out_arcs(7, (10, 6))
g.set_out_arcs(8, (6,))
g.set_out_arcs(9, (12, 11))
g.set_out_arcs(10, (7, 6))
g.set_out_arcs(11, (12, 9, 0))
g.set_out_arcs(12, (11, 9, 1))
for i in g.dfstraverse():
    print(i)
print("____________")
for i in g.bfstraverse():
    print(i)

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__空无一人__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值