【问题标题】:Exit DFS Recursion When Target Vertex Is Found And Return Path找到目标顶点并返回路径时退出 DFS 递归
【发布时间】:2021-06-30 23:08:31
【问题描述】:

我做了一个递归 DFS 算法,它可以在找到目标时返回路径。请注意,我正在利用递归,并尝试在路径保存中使用尽可能少的内存。当找到目标时,保证path 将包含正确的路径。但是随后 DFS 必须完全停止,否则由于之后的pop()s,我无法返回正确的列表。临时解决方案是全局列表result。有什么办法:

  1. 找到目标后停止递归?
  2. 在指定点返回path 列表?
result = []

def dfs(graph, vertex, visited, path):

    global result
    if vertex not in visited:
        visited.add(vertex)
        if isTarget(vertex):
            print("Solution found ! " + str(path))
            result = path.copy() # recursion must stop here and return path at this state
        for neighbor in graph.getSuccessors(vertex):
            path.append(neighbor[1]) #neighbor[1] is direction 
            print("Visiting node" + str(neighbor[0]))
            dfs(graph, neighbor[0], visited, path)
            path.pop()

【问题讨论】:

  • 你试过把else放在最后for之前吗?
  • @testing_22 是的,没有区别。

标签: python algorithm recursion search depth-first-search


【解决方案1】:

我建议将搜索逻辑与遍历逻辑分开。这允许您以通用方式编写 dfs 并重用它来遍历您的图形以进行任何与图形相关的操作 -

def dfs(graph, vertex, path = tuple(), visited = set()):
  if vertex in visited: return
  yield (vertex, path)
  for [v,dir] in graph.getSucessors(vertex):
    yield from dfs(graph, v, (*path, dir), {*visited, v})

现在find 只是我们可以围绕dfs 编写的众多函数之一-

def find(graph, start, target):
  for (v, path) in dfs(graph, start):
    if v == target:
      return (v, path)
  return (None, None)

dfs 是惰性的,因此一旦find 返回,迭代就会停止。这是一个如何使用它的示例 -

(vertex, path) = find(graph, startVertex, targetVertex)
if not vertex:
  print("target not found")
else:
  print(f"found {vertex} at path {path}")

这种方法的一个优点是不仅可以找到第一个目标,还可以找到所有个目标 -

def find_all(graph, start, target):
  return list((v, path) for (v, path) in dfs(graph, start) if v == target)

如果您分享graph.getSuccessors,我相信我们也可以对其进行优化。如果你像dfs 那样把它写成懒惰的,那么两个生成器都可以从提前退出行为中受益。

【讨论】:

  • 我也喜欢这种方法,+1
  • 我忘了提到可以恢复暂停的生成器,这使得编写 find_all 之类的东西变得超级容易。有关详细信息,请参阅编辑:D
【解决方案2】:

在我看来,dfs() 可以返回一个列表,这将允许我们继续/中断递归。比如:

result = []

def dfs(graph, vertex, visited, path):

    if vertex not in visited:
        visited.add(vertex)
        if isTarget(vertex):
            print("Solution found ! " + str(path))
            return path # recursion stops here and returns path at this state
        for neighbor in graph.getSuccessors(vertex):
            path.append(neighbor[1]) #neighbor[1] is direction 
            print("Visiting node" + str(neighbor[0]))
            temp_path = dfs(graph, neighbor[0], visited, path)
            if temp_path:
                return temp_path # break recursion since path found
            path.pop()
    return [] # if no path/target node found

result = dfs()

【讨论】:

  • @NickDelta 考虑投票,如果它解决了你的目的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
相关资源
最近更新 更多