加法和+ =给出不同的列表结果(深度优先搜索)

时间:2018-01-06 12:59:11

标签: python list depth-first-search

我一直在努力了解深度优先搜索,并在线使用各种来源获得以下代码:

graph = {'A': ['B', 'D'], 'B': ['E'], 'C': [], 'D': ['C', 'E'], 
         'E': ['H', 'I', 'J'], 'F': [], 'G': [], 'H': ['F'], 
         'I': [], 'J': ['G']}

def dfs(graph, start, end, path=None):
    if path == None:
        path = []
    path = path + [start]
    paths = []
    if start == end:
        return [path]
    for neighbour in graph[start]:
        if neighbour not in path:
            paths.extend(dfs(graph, neighbour, end, path))
    return paths

print(dfs(graph, 'A', 'G'))

这会输出所需的结果:

[['A', 'B', 'E', 'J', 'G'], ['A', 'D', 'E', 'J', 'G']]

但当我用path = path + [start](或path += [start]替换行path.extend([start])时,我理解同样的事情)我得到以下输出:[['A', 'B', 'E', 'H', 'F', 'I', 'J', 'G', 'D', 'C']]

我知道这与操作上的差异有关,但我真的不明白它在这里是如何应用的。请有人解释一下吗?

1 个答案:

答案 0 :(得分:7)

path = path + [start]

略有不同
path += [start]  # or path.extend([start])

用于列出(以及其他可变类型),因为它会重新创建path的新引用(隐含的是你想要的,你不想写入之前的引用)

path += [start]  # or path.extend([start])

重复使用相同的引用,因为您在循环中多次传递path(无需复制):

for neighbour in graph[start]:
    if neighbour not in path:
       paths.extend(dfs(graph, neighbour, end, path))

因此,如果某个其他对象存储在存储中,您将更改这两个列表:不是相同的行为,而不是您想要的行为。

当然你可以做paths.extend(dfs(graph, neighbour, end, path.copy())),但这违反了来电者的最小声音原则(它不会期望修改最后一个参数)

我的建议:

  • 如果您想要表现并且不在乎重复使用引用,请始终使用+=作为列表,因为它只是扩展了列表。 +运算符会创建一个新列表和副本,这实际上要慢一些。
  • path = path + something使用list类型时,请始终为未来的维护者(包括您自己)添加评论。不要使用+=优化。< / LI>

可能是一些更明确和等效的代码:

path = path.copy() # or path[:], or list(path)...: force creation of a new reference to break dependency with passed parameter
path += [start]

另请注意:它不适用于strtuple类型,因为即使+=创建了新引用,因为字符串不变性 。不存在与字符串共享引用的风险,因此在此使用tuple代替list也可以修复它:

if path == None:
    path = tuple()
path += (start,)  # += creates a new path reference, cos path is a tuple, immutable

(但在这种情况下,不要期望使用+=获得更高的效果,制作副本)