返回目标路径的深度优先图搜索

时间:2011-09-10 22:10:46

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

我整个星期都在尝试这一点,但在我的生活中,我不能想出来。

我知道我需要一个辅助函数来递归并返回pathSoFar。我似乎无法理解递归。

我很困惑,除了递归之外,我甚至无法确切地解决问题。

感谢您的帮助。

编辑:好的,我会澄清一下。令我困惑的一件事是当节点没有邻居时返回什么路径。可以首先返回目标路径,但是,因为帮助程序仍在递归,它可以返回死端路径。我想我对回溯感到困惑。

2 个答案:

答案 0 :(得分:6)

Wikipedia实际上有一些非常好的伪代码用于深度优先遍历。这些遍历算法使用它们在遍历中出现的顺序标记图中的所有节点。相反,您希望在找到目标时立即返回目标路径。

让我们修改维基百科算法:

( INCORRECT ALGORITHM DELETED WHICH THE OP COMMENTED ON CORRECTLY BELOW )

这是一个Python实现:

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

def DFS(g, v, goal, explored, path_so_far):
    """ Returns path from v to goal in g as a string (Hack) """
    explored.add(v)
    if v == goal: 
        return path_so_far + v
    for w in g[v]:
        if w not in explored:
            p = DFS(g, w, goal, explored, path_so_far + v)
            if p: 
                return p
    return ""

# Hack unit test
assert DFS(g, 'A', 'I', set(), "") == "ABEGI"
assert DFS(g, 'A', 'E', set(), "") == "ABE"
assert DFS(g, 'B', 'B', set(), "") == "B"
assert DFS(g, 'B', 'B', set(), "") == "B"
assert DFS(g, 'A', 'M', set(), "") == ""
assert DFS(g, 'B', 'A', set(), "") == "BCA"
assert DFS(g, 'E', 'A', set(), "") == ""

这里的想法是,您希望在图g中找到从vgoal的路径,因为您已经沿path_so_far路径前进}。 path_so_far实际上应该在v之前结束。

如果目标是v,那么您可以将v添加到目前为止的路径,就是这样。

否则,您将需要探索从v发出的所有边缘,这些边缘尚未在边缘的另一端探索过节点。对于这些边缘中的每一个,您可以使用到目前为止的路径(当前节点)进行搜索(递归)。如果v没有通往目标的路径,您将返回空路径。

好处是你使用递归来“自动回溯”,因为你将增强路径传递给你的递归调用。

答案 1 :(得分:1)

递归是指将问题减少为一系列较小的问题。

在这种情况下,假设您正在尝试查找从节点A到节点Z的路径。首先,您要查看A的邻居。假设它们是B,C和D.

现在你有三个子问题:找到从B到Z,C到Z和D到Z的路线。如果你能解决其中任何一个问题,你也解决了从中找到路径的更大问题A到Z。

所以,你递归。你在B,C和D上使用你的findPath方法,给每个人一个包含A的节点列表 - 以防止它们向后移动[1]。如果他们中的任何一个说“我找到了一条路”,你就会走这条路,他们会回来,在一开始就把A贴上,并称之为一天。

在递归调用中,最终您会发现自己处于Z的邻居节点(如果A和Z实际连接)。当发生这种情况时,您已解决了问题:返回该链接。如果你最终到达一个已经访问过每个邻居的死端节点,那么返回一些代码,让你的调用者知道它是一个死胡同,他们不应该使用该节点来尝试构建一个解决方案。

[1]旁注:如果你非常聪明,你也会把B放在你传递给C上的递归调用的列表中,并将B + C放在你传递给D的列表中。