算法——广度优先搜索

Posted 代码综合征

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法——广度优先搜索相关的知识,希望对你有一定的参考价值。

本文介绍图以及与图相关的算法——广度优先搜索。

广度优先搜索能让你找出两样东西之间最短的距离,但是最短距离可以有多重含义,如国际跳棋,计算走多少步就可以获胜。

图简介

要求从一地前往另一点的最短路径,称为最短路径问题。解决最短路径问题的算法被称为广度优先搜索。

图是一组连接的模拟,图由节点和边组成。一个节点可能与众多节点相连,这些节点被称为邻居。

也就是图用于模拟不同的东西是如何相连的。

广度优先搜索

关于图有两类问题,一类是从节点A出发,有前往节点B的路径吗?第二类是从节点A触发,前往节点B的哪条路径最短?

例如一个人的关系网,朋友是一度关系,朋友的朋友是二度关系。

广度优先算法是先在一度关系里搜索,再在二度关系里搜索,在广度优先搜索的执行中,搜索范围从起点开始逐渐向外延伸。

也可以这样看,一度关系在二度关系之前加入查找名单,那么有一种数据结构能够支持这个目的,那就是队列。

队列

队列支持两种操作,入队和出队。队列是一种先进先出的数据结构,而栈是一种后进先出的结构。

图的每个节点都与邻近点相连,如何表示“你->Bob”这样的关系?可以使用散列表,在python中就是dict。

比如,表示我与其他相连的关系,可以这么写:

 
   
   
 
  1. graph = {}

  2. graph["you"] = ["alice", "bob", "claire"]

在字典中间,一个key映射了一个数组,包含了所有的邻居。对于更大更复杂的图,则可以把每一个节点的邻居列出来。如:

 
   
   
 
  1. graph = {}

  2. graph["you"] = ["alice", "bob", "claire"]

  3. graph["bob"] = ["anuj", "peggy"]

  4. graph["alice"] = ["peggy"]

  5. graph["claire"] = ["thom", "jonny"]

  6. graph["anuj"] = []

  7. graph["peggy"] = []

  8. graph["thom"] = []

  9. graph["jonny"] = []

键值对的添加顺序没有影响,因为散列表是无序的。

在上面的例子中,有的节点没有邻居,这是因为这是一个有向图,其中的关系是单向的。而对于无向图,直接相连的节点互为邻居。

实现算法

首先创建一个队列,在python中可以使用deque来创建一个双端队列。

 
   
   
 
  1. from collections import deque

  2. search_queue = deque()

  3. search_queue += graph["you"]

  4. while search_queue:

  5.    person = search_queue.popleft()

  6.    if person_is_seller(person):

  7.        print person + " is a mango seller!"

  8.        return True

  9.    else:

  10.        search_queue += graph[person]

  11.    return False

  12. def person_is_seller(name):

  13.    return name[-1] == 'm' #只是一个判断的示例

这个算法将被不断执行,直到找到一个结果,或者队列变成空。

不过这个算法还有个问题,就是如果检查一个元素前,必须确认之前是没有检查过的。因为如果一个元素能够多次检查,可能会造成无限循环。

最后广度优先算法的代码为:

 
   
   
 
  1. def search(name):

  2.    search_queue = deque()

  3.    search_queue += graph[name]

  4.    searched = []

  5.    while search_queue:

  6.        person = search_queue.popleft()

  7.        if not person in searched:

  8.            if person_is_seller(person):

  9.                print person + " is a mango seller!"

  10.                return True

  11.            else:

  12.                search_queue += graph[person]

  13.                searched.append(person)

  14.    return False

运行时间

搜索图的时候,意味着将沿着每条边进行,因此运行时间至少为 O(边数)

同时还使用了队列,包含要检查的每个节点,讲一个节点添加到队列所需时间是固定的,为O(1),因此对每个人都这么做的总时间为 O(人数)

所以广度优先的运行时间就是 O(节点数+边数),也就是 O(V+E),V是顶点数,E为边数。

小结

  • 广度优先搜索指出是否有从A到B的路径。

  • 如果有,广度优先搜索将找出最短路径。

  • 面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来 解决问题。

  • 有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱。

  • 无向图中的边不带箭头,其中的关系是双向的,例如,ross - rachel表示“ross与rachel约 会,而rachel也与ross约会”。

  • 队列是先进先出(FIFO)的。

  • 栈是后进先出(LIFO)的。

  • 你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必 须是队列。

  • 对于检查过的人,务必不要再去检查,否则可能导致无限循环。


以上是关于算法——广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章

算法之广度优先搜索

图相关算法

七十九深度和广度优先搜索算法

基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

算法浅谈——走迷宫问题与广度优先搜索

基础扩展 | 16. 队列应用示例:广度优先搜索