图的遍历有深度优先搜索和广度优先搜索两种
深度优先搜索
类似于树的先根遍历,但图不同于树的地方在于,它可能存在回路/环,那么在进行遍历的时候,同一个顶点可能会被多次搜索到,如果一个顶点被访问过了,要进行标记,当它再次被搜索到,不再对其进行访问。图的深度优先遍历的过程是,任意选定一个顶点,访问它,然后依次对它的邻接顶点进行深度优先遍历,这是一个递归的过程,通过深度优先访问到的顶点都是第一个选定的顶点能够到达的顶点,但图有可能不是联通的,所以当选定一个顶点进行深度优先遍历的时候,不一定能够把所有的顶点都给搜索到,因此有可能需要进行多次深度优先遍历。通过上面的叙述,我们需要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)