遍历
我们以前遍历过树,用了几种办法,同样的,这样的思路也可以应用于图。
例如,对于下图:
用深度优先搜索的办法,我们随便指定一个顶点为初始顶点(因为图种没有第一个顶点这个概念,可以人为指定),如a,先输出a,再看邻接点(b,d,c),我们递归转移到b,对b点,也是先输出,再看它的临界点(d,a),我们转移到d,对d点,还是先输出,再看临界点(b,a)。好家伙,又回到了以前的顶点b和a了,这肯定要避免,所以得有一个是否访问过某个顶点的标志。根据这个标志,我们知道d的邻接点b和a都访问过了,所以递归返回,回到了b点,再看它的下一个邻接点a,也是访问过了,所以递归返回,回到a点,在看a的下一个邻接点d,访问过,再看a的下一个邻接点c,递归转移到c,对c点,也是先输出,再看它的邻接点a,访问过了。至此a的全部邻接点都走完了,整个递归过程结束。
用广度优先搜索的办法,我们也是随便指定一个顶点为初始顶点,如a,我们使用一个列表,先把a入列,并记录已访问过。然后对这个列表循环执行如下操作:
从队列种弹出第一个顶点,先输出a,再看邻接点(b,c,d),把邻接点入列,并记录已访问过。(所以广度优先的访问标志跟深度优先的标志含义有点不同)
代码如下:
class Graph(object):
def __init__(self,vertex,edge):
self.MAX_INT=-1
self.vertex=vertex #顶点,一维数组
self.vsize=len(self.vertex)
self.v=[]
for i in range(self.vsize):
self.v.append(i)
self.edge=edge #边,二维数组
self.visited=[0]*self.vsize #是否访问过
def DFS(self,vidx):
startv = self.vertex[vidx]
print(startv)
self.visited[vidx]=1
adjv=self.edge[vidx]
for i in range(self.vsize):
if adjv[i]!=self.MAX_INT and self.visited[i]==0:
self.DFS(i)
def BFS(self,vidx):
que=[] #访问节点队列
visiting=[0]*self.vsize
que.append(vidx)
visiting[vidx]=1 #访问标志
while len(que)>0:
idx=que.pop(0)
startv = self.vertex[idx]
print(startv)
adjv=self.edge[idx]
for i in range(self.vsize): #增加邻接点
if adjv[i]!=self.MAX_INT and visiting[i]==0:
que.append(i)
visiting[i]=1
用一段程序初始化一个图:
def buildGraph():
MAX_INT=-1
vertex=['a','b','c','d']
edge=[[MAX_INT,1,1,1],
[1,MAX_INT,MAX_INT,1],
[1,MAX_INT,MAX_INT,MAX_INT],
[1,1,MAX_INT,MAX_INT]]
return Graph(vertex,edge)
我这里用的邻接矩阵来存储的数据。
测试一下:
udg=buildGraph()
udg.DFS(0)
udg.BFS(0)
运行结果如下:
a b d c
a b c d
对有向图也是可以的,如:
只要把edge变成:
edge=[[MAX_INT,MAX_INT,1,1],
[MAX_INT,MAX_INT,MAX_INT,MAX_INT],
[MAX_INT,MAX_INT,MAX_INT,MAX_INT],
[MAX_INT,1,MAX_INT,MAX_INT]]
再次运行就可以了:
a c d b