【问题标题】:BFS algorithm in PythonPython中的BFS算法
【发布时间】:2014-05-05 17:08:54
【问题描述】:
graph={ 0:[1,3,4], 1:[0,2,4], 2:[1,6], 3:[0,4,6], 4:[0,1,3,5], 5:[4], 6:[2,3] }

def bfs(graph, start, path=[]):
    queue = [start]
    while queue:
        vertex = queue.pop(0)
        if vertex not in path:
            path.append(vertex)
            queue.extend(graph[vertex] - path)
    return path

print bfs(graph, 0)

伙计们!有人可以帮我处理这个 bfs 代码吗?我不明白如何解决这个排队问题。

【问题讨论】:

  • “解决”是什么意思?解决方案应该是什么?此外,请注意在 Python 中将默认参数设置为 []。见this article
  • 我认为通过“解决此队列行”,他的意思是,诊断以queue.extend 开头的行上发生的错误。即TypeError: unsupported operand type(s) for -: 'list' and 'list'
  • 顺便提一下,OP,请注意函数定义中的path=[] - 如果您多次运行此函数,您可能会得到令人惊讶的结果。请参阅this 关于默认可变参数的问题。

标签: python algorithm graph breadth-first-search


【解决方案1】:

要使用路径上尚未看到的所有节点来扩展队列,请使用集合操作:

queue.extend(set(graph[vertex]).difference(path))

或使用生成器表达式:

queue.extend(node for node in graph[vertex] if node not in path)

列表不支持减法。

您并不真正需要过滤节点,但是,您的代码可以使用简单的:

queue.extend(graph[vertex])

if vertex not in path: 测试还可以防止重新访问节点。

您不应该使用列表作为默认参数,请参阅"Least Astonishment" and the Mutable Default Argument;你根本不需要默认参数:

def bfs(graph, start):
    path = []

演示:

>>> graph={ 0:[1,3,4], 1:[0,2,4], 2:[1,6], 3:[0,4,6], 4:[0,1,3,5], 5:[4], 6:[2,3] }
>>> def bfs(graph, start):
...     path = []
...     queue = [start]
...     while queue:
...         vertex = queue.pop(0)
...         if vertex not in path:
...             path.append(vertex)
...             queue.extend(graph[vertex])
...     return path
... 
>>> print bfs(graph, 0)
[0, 1, 3, 4, 2, 6, 5]

【讨论】:

  • 使用 queue.extend(graph[vertex]) 得到相同的结果。
  • @PadraicCunningham:当然;因为vertex not in path 测试也会过滤。好点子。
  • if vertex not in path: 支票很贵...可以提高效率吗?我知道路径必须包含顺序。也许,可以使用第二组来测试成员资格。
  • @cᴏʟᴅsᴘᴇᴇᴅ:我过去曾尝试过这个;除非您的路径很长,否则通常不值得付出努力。
【解决方案2】:
queue.extend(graph[vertex] - path)

这一行给出TypeError: unsupported operand type(s) for -: 'list' and 'list',因为你不能减去两个列表。您可以将它们转换为确实支持差异的不同集合。例如:

graph={ 0:[1,3,4], 1:[0,2,4], 2:[1,6], 3:[0,4,6], 4:[0,1,3,5], 5:[4], 6:[2,3] }

def bfs(graph, start, path=[]):
    queue = [start]
    while queue:
        vertex = queue.pop(0)
        if vertex not in path:
            path.append(vertex)
            queue.extend(set(graph[vertex]) - set(path))
    return path

print bfs(graph, 0)

结果:

[0, 1, 3, 4, 2, 6, 5]

顺便说一句,修改参数列表可能会很好,这样您就没有可变列表作为默认值:

def bfs(graph, start, path=None):
    if path == None: path = []

【讨论】:

  • 您不需要将两者都转换为集合(set.difference() 接受任何可迭代对象)并且 list.extend() 也接受任何可迭代对象,因此 list() 调用也是多余的。
  • 对不必要的list 电话进行良好观察。已编辑。但是,如果想要使用减号运算符,看起来两个set 转换都是必要的。不过,正如您所说,明确的 difference 调用可能会获取一个列表。
  • 这里也只需要 queue.extend(graph[vertex])。
  • queue.extend(set(graph[vertex]) - set(path) - set(queue)) 为了避免在队列中多次添加尚未访问的节点。
【解决方案3】:

Bug 是没有列表差异方法。您可以将其转换为设置并使用设置差异方法,也可以将列表理解用作

queue.extend(graph[vertex] - path)

可以替换为

queue += [i for i in graph[vertex] if i not in path].

【讨论】:

    【解决方案4】:
     #USE BELOW CODE FOR SIMPLE UNDERSTANDING
    
        
    
      
    graph = {
        'A' : ['B' , 'C','D'],
        'B' : ['E'],
        'C' : ['F'],
        'D' : ['G'],
        'E' : [],
        'F' : ['Z'],
        'G' : [],
        'Z' : [],
    }
    
    
    visited = [] #Store visted nodes
    queue = [] #BFS uses queue structure so this varible will work like QUEUE ( LIFO)
    final_result = [] 
    
    def bfs(visited,graph,node):
        visited.append(node)
        queue.append(node)
        
        while queue:
            s = queue.pop(0)
            print(s,end=" ")
            #final_result.append(s)
            
            for neighbour in graph[s]:
                if neighbour not in visited:
                    visited.append(neighbour)
                    queue.append(neighbour)
        
    
        bfs(visited,graph,'A')
        print(final_result) 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-20
      • 2016-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 2022-07-18
      • 1970-01-01
      相关资源
      最近更新 更多