1 非递归深搜
图的深搜递归形式非常简单,相信大家都会,在此就来实现一下非递归版本的深搜。
1.1 图示
对于以上的图,从1开始的深搜遍历结果应该是1 2 3 4 0。那么如何通过非递归形式得到该结果呢,下面以该图为例进行演示:
首先我们准备要一个栈来模拟递归的过程,以及一个集合来存储已经访问的节点,以免因为图中的环结构让子节点再次进入父节点访问。
我们首先处理节点1,这里将入栈操作视为对节点的访问,于是我们将节点1入栈并访问,再加入已访问集合。
从这开始,我们就要对栈中的元素进行不断地访问,直到栈为空。我们先将栈顶元素1出栈,并从其子节点中选择一个未访问的节点进行访问。由于子节点可能还有子节点,在此将父节点和子节点一起入栈,并加入集合(以下省略)。
再次获取栈顶元素,访问子节点。
再次获取栈顶元素,访问子节点。
再次获取栈顶元素,访问子节点。可以发现此时的栈顶节点已经没有任何的子节点可以访问,对此我们不做任何其他操作,任其出栈。
再次获取栈顶元素,访问子节点。
再次获取栈顶元素,访问子节点。此时的节点2还有子节点0,访问子节点,进入分支。
再次获取栈顶元素,访问子节点。
此时栈还未空,继续获取栈顶元素,访问子节点。
继续获取栈顶元素,访问子节点。
可以发现此时栈为空了,遍历也由此结束,对比一下访问结果,与上是完全相同的。
1.2 代码
理解了图示的过程,代码也就十分简单了。代码中的图是通过邻接表的方式实现的,每个节点都有一个出边集合outEdges与入边集合inEdges,且图对象拥有一个顶点集合verteces用于存储所有的顶点,具体可见使用邻接表实现数据结构图(python)。
def dfs_nonrecursion(self,v):
print('depth first search without recursion----------------')
start_vertex=self.vertices.get(v)
visited_vertex=set()#已访问顶点集合
stack = LifoQueue() # 创建栈
#将顶点入栈,表示访问该节点,打印value
stack.put(start_vertex)
print(start_vertex.value)
visited_vertex.add(start_vertex)
while not stack.empty():
vertex=stack.get()#出栈,对该节点的子节点进行访问
for edge in vertex.outEdges:
if edge.to in visited_vertex:#已访问节点
continue
else:
print(edge.to.value)#访问子节点内容
visited_vertex.add(edge.to)
stack.put(vertex)#父节点与子节点入栈
stack.put(edge.to)
break