这个Python实现的深度优先搜索输出为什么会改变?

2024-09-22 20:26:01 发布

您现在位置:Python中文网/ 问答频道 /正文

对于深度优先搜索,我有一个Python实现,如下所示:

def dfs(graph, current_vertex, target_value, visited=None):
  if visited is None:
    visited = []

  visited.append(current_vertex)

  if current_vertex == target_value:
    return visited


  for neighbor in graph[current_vertex]:
    if neighbor not in visited:
      path = dfs(graph, neighbor, target_value, visited)

      if path:
        return path


my_graph = {
    'lava': set(['sharks', 'piranhas']),
    'sharks': set(['lava', 'bees', 'lasers']),
    'piranhas': set(['lava', 'crocodiles']),
    'bees': set(['sharks']),
    'lasers': set(['sharks', 'crocodiles']),
    'crocodiles': set(['piranhas', 'lasers'])
  }

但是当我运行print(dfs(my_graph, "crocodiles", "bees"))时,有时我得到[‘crocodiles’, ‘piranhas’, ‘lava’, ‘sharks’, ‘lasers’, ‘bees’],有时我得到[‘crocodiles’, ‘lasers’, ‘sharks’, ‘lava’, ‘piranhas’, ‘bees’],有时我得到:[‘crocodiles’, ‘piranhas’, ‘lava’, ‘sharks’, ‘bees’]。为什么同一输入的输出不同?这个实现是否正确?你知道吗


Tags: targetifvaluecurrentgraphvertexlavaset
2条回答

那是因为你还没有考虑回溯。例如,假设你的DFS决定去[‘crocodiles’, ‘lasers’, ‘sharks’, ‘lava’, ‘piranhas’],这会导致一个死胡同。现在,即使已经到了死胡同,‘lava’, ‘piranhas’已经被追加,所以当您返回到'sharks'并正确地选取'bees'时,列表输出不正确。你知道吗

要解决此问题,只需在从当前节点创建路径之前记录visited。创建路径后,请检查目标节点是否存在,如果不存在,请将visited设置回其原始状态:

def dfs(graph, current_vertex, target_value, visited=None):
  if visited is None:
    visited = []

  visited.append(current_vertex)

  if current_vertex == target_value:
    return visited


  for neighbor in graph[current_vertex]:
    if neighbor not in visited:
      orig = list(visited)
      path = dfs(graph, neighbor, target_value, visited)
      if path and target_value in path:
        return path
      visited = list(orig)

编辑:

我还应该注意到list(visited)list(orig)是用来做什么的。这样做的原因是(在本例中)深度复制列表。这意味着修改一个将完全独立于另一个。这只适用于深度为1的列表。如果列表的深度大于1,则只需将引用复制到列表中的列表,然后运行到相同的问题。在这种情况下,通过如下方式导入copy中的deepcopy

from copy import deepcopy

编辑2:

最好按以下方式执行,因为您不必存储列表的副本:

def dfs(graph, current_vertex, target_value, visited=None):
  if visited is None:
    visited = []

  visited.append(current_vertex)

  if current_vertex == target_value:
    return visited


  for neighbor in graph[current_vertex]:
    if neighbor not in visited:
      path = dfs(graph, neighbor, target_value, visited)
      if path and target_value in path:
        return path
      visited.pop(-1)

因为在Python中,集合没有特定的顺序。您可能希望使用列表而不是集合。你知道吗

相关问题 更多 >