小BFS细节澄清

时间:2017-01-26 02:53:30

标签: algorithm optimization breadth-first-search

标准的bfs实现类似于(由维基百科提供):

 Breadth-First-Search(Graph, root):
    create empty set S
    create empty queue Q      
    root.parent = NIL
    Q.enqueue(root)                      
    while Q is not empty:
        current = Q.dequeue()
        if current is the goal
            return current
        for each node n that is adjacent to current:
            if n is not in S:
                add n to S
                n.parent = current
                Q.enqueue(n)

我想知道为什么在查看与当前相邻的邻居时,无法检查电流是否是目标。对于前者类似的东西:

 Breadth-First-Search(Graph, root):
    create empty set S
    create empty queue Q      
    root.parent = NIL
    if root is the goal
        return root
    Q.enqueue(root)                      
    while Q is not empty:
        current = Q.dequeue()
        for each node n that is adjacent to current:
            if n is the goal          // check here instead
                  n.parent = current
                  return n
            if n is not in S:
                add n to S
                n.parent = current
                Q.enqueue(n)

这个想法是,一旦在邻居中找到它,你就会抓住这个词。您可以确保这是最短的路径,因为队列中的路径不可能已经包含路径,因为我们在它发生之前就已经捕获了该路径。

据我所知,这需要在while循环之前添加一个额外的检查,以查看root是否是目标,但除此之外,是否有一些原因bfs没有像这样实现?它在技术上应该更快吗?

2 个答案:

答案 0 :(得分:1)

如果您对根进行检查,您的版本可以正常工作(您应该将其放在问题中)。

在某些情况下,您的方式会更快,在某些情况下会更慢。例如,如果存在某种惩罚(如额外的缓存未命中)以便两次访问每个节点的内容,它可能会更慢。

通常差异并不显着,人们只是因为代码更简单而第一种方式。

答案 1 :(得分:0)

我想我会进一步重构它。我注意到root没有直接添加到S中,这意味着它会在以后添加,然后再次检查。我在早期根返回后移动了S和Q的创建。切换while,这意味着root不必排入Q然后检查Q以查看root是否在其中然后将root出列。我将S检查移动到每个循环的第一个内部,因为该检查将阻止目标检查每次循环一次或多次,目标检查只会阻止S检查一次。它还让我删除了n.parent =当前代码行重复,没有帮助性能,但我不喜欢重复。

 Breadth-First-Search(Graph, root):
    root.parent = NIL
    if root is the goal
        return root
    create empty set S
    add root to S
    create empty queue Q
    current = root
    while true
        for each node n that is adjacent to current:
            if n in S:
                continue
            n.parent = current
            if n is the goal
                return n
            add n to S
            Q.enqueue(n)
        if Q empty
            break
        current = Q.dequeue()