【问题标题】:Is this a breadth-first search algorithm?这是广度优先搜索算法吗?
【发布时间】:2017-05-04 18:38:32
【问题描述】:

所以,我有这张图,我想使用广度优先搜索算法来查看是否存在从一个顶点到另一个顶点的路径。

所以,我在 python 中实现了一个函数,它根据路径的存在返回 true 或 false,并且它可以工作。好吧,它适用于我所做的测试。我想知道的是这是否确实是一种呼吸优先搜索算法。我之前没有见过任何 BFS 算法,我只知道它的基本思想。我听说 BFS 是递归实现的,虽然我是迭代实现的,这就是为什么我对此表示怀疑。所以,这是我的图表的函数和表示:

outb = {1: [2, 3],
  2: [4, 5],
  3: [5, 11, 12],
  4: [6, 7],
  5: [7],
  6: [9, 10],
  7: [8],
  11: [3],
  12: [15, 14, 13],
  13: [17],
  14: [17],
  15: [12, 5, 8, 16],
  17: [18]}

def BFS(v1, v2):
    parsed = []
    toParse = [v1]
    current = v1

    while len(toParse) > 0:

        while current in parsed:
            current = toParse.pop(0)

        if current not in outb:
            return False

        if v2 in outb[current]:
            return True

        toParse += outb[current]
        parsed.append(current)

    return False

我的最后一个问题是:BFS 是否就其本质而言是寻找从一个顶点到另一个顶点的最短路径?我在互联网上看到了这件事,我想确定一下。

【问题讨论】:

  • 阅读wikipedia page。看起来您的代码在那里实现了算法,并声明 BFS 找到了最短路径。
  • 将您的代码与维基百科中的伪代码进行比较,S == parsedQ == toParsecurrent == current
  • 你的代码是BFS,但也是错误的,因为current not in outb不代表没有路径,你尝试做toParse.pop(0)而不考虑toParse是否真的有任何元素.此外,对于大多数使用的数据结构来说,列表并不是一个有效的选择。
  • @user2357112 current not in outb 是错误检查,以确保您没有从不在图中的节点寻找路径。此外,代码会检查 toParse 是否有任何元素。 pop 调用发生在 while 循环中,并以此为条件。
  • @DanHall:图中有些节点不是in outb,因为有人选择在outb 中省略没有出边的键。如果搜索在到达目的地之前就到达了这样一个节点,搜索会错误输出False

标签: python graph-theory breadth-first-search


【解决方案1】:

这是一种广度优先搜索。它遵循一个相当典型的结构,将搜索边界视为一个队列(尽管列表对于队列来说是一种低效的选择),并且它按照与根的距离顺序来考虑节点,就像标准的广度优先搜索一样。

然而,这也是错误的。 current not in outb 终止条件导致它在 wrongly output False 中搜索 BFS(1, 18),而 while current in parsed: current = toParse.pop(0) 循环可以耗尽 toParse 并在尝试从空列表中弹出时抛出异常,demonstrated here不同的图表。此外,您的 outb 与它应该代表的图形不匹配;它缺少一堆后边缘,例如 6->4。

【讨论】:

  • 所以如果我纠正这些错误和图形表示,它可以被认为是一个“合法”的 BFS 算法?
  • @Xyntell:我已经认为它是 BFS,但它不是你想要的 BFS。
  • 好的。知道了!感谢您的回复。
  • @Xyntell 代码在我的回答中纠正了这些错误(减去缺少的后边缘,如果你想考虑它们,你必须添加到字典中)。
【解决方案2】:

这是一种 BFS 算法,用于查找路径是否存在,但它不会告诉您该路径是什么,也不会说明您的字典的结构以表示图形的方式。

以下是上述图表的 BFS 示例,它可以处理字典表示图表的方式。它在找到路径时返回路径,在路径不存在时返回 False。如果您只想让它在找到路径时返回 True,请将第 19 行编辑为 return True

def BFS2(graph, v1, v2):
    '''
    graph: a dictionary representing an unweighted graph
    v1: a key in graph, representing the start node
    v2: a key and value in graph, representing the end node
    returns: a shortest path from v1 to v2, False if there is no path.
    '''
    if v1 not in graph:
        return False
    path_start = [v1]
    paths = [path_start]
    while len(paths):
        test_path = paths.pop(0)
        last_node = test_path[-1]

        for next_node in graph[last_node]:
            if next_node not in test_path:
                next_path = test_path + [next_node]
                if next_node == v2:
                    paths.append(next_path)
                    return next_path
                elif next_node in graph:
                    paths.append(next_path)
    return False

【讨论】:

  • 不要求 BFS 必须实际返回路径。搜索是否是广度优先搜索只是搜索结构的一个属性,而不是它输出什么的问题。
  • @user2357112 明白了。谢谢!看起来我需要重新审视我的图论。编辑以反映这一点。
  • 更好,但你的实现是错误的。如果v1 没有出边,它会失败,并且由于它没有使用访问集,它可以执行指数级的冗余工作。 (尝试使用路径作为访问集并不能阻止它冗余地考虑到同一个节点的许多不同路径。)
  • @user2357112 已修复以处理客户端正在搜索从没有出边的节点开始的路径的情况。但是,它确实考虑了访问节点,因为它仅在 next_node 不在 test_path 中时添加子节点
  • 不过,这只会阻止它尝试循环返回自身的路径。它不会阻止搜索将 500 亿条路径放置到 paths 中的同一节点并独立扩展它们中的每一个。这不是正确性问题,但它会阻止搜索在合理的时间内找到目的地,即使对于相当小的图形也是如此。 Demo.(这不是唯一的低效率,但它的影响最大。)
【解决方案3】:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多