欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【算法】广度优先搜索

程序员文章站 2022-05-21 11:25:37
...

广度优先搜索(breadth first search)

最短路径问题(shorterst-path problem)

解决最短路径问题的算法被称为广度优先搜索

最短路径问题解决步骤

(1) 使用来建立问题模型。

(2) 使用广度优先搜索解决问题。

 

图的定义

图模拟一组连接。

图由节点(node)和(edge)组成。一个节点可能与众多节点直接相连,这些节点被称为邻居。图用于模拟不同的东西是如何相连的

 

广度优先搜索

广度优先搜索是一种用于图的查找算法,可帮助回答两类问题。

  •   第一类问题:从节点A出发,有前往节点B的路径吗?
  •   第二类问题:从节点A出发,前往节点B的哪条路径最短?
查找最短路径

在广度优先搜索的执行过程中,搜索范围从起点开始逐渐向外延伸,即先检查一度关系,再检查二度关系。

广度优先搜索不仅查找从A到B的路径,而且找到的是最短的路径。

 

队列

需要按添加顺序进行检查。可以用队列来实现这种目的

队列类似于栈,不能随机地访问队列中的元素。

队列只支持两种操作:入队出队

队列是一种先进先出(First In First Out,FIFO)的数据结构,而是一种后进先出(Last InFirst Out,LIFO)的数据结构。

 

 

实现图

使用散列表将键映射到值,用来实现图

 

示例:

>>> graph={}
>>> graph['you']=['alice','bob','claire']
>>> graph
{'you': ['alice', 'bob', 'claire']}
>>> graph['bob']=['anuj','peggy']
>>> graph['alice']=['peggy']
>>> graph['claire']=['thom','jonny']
>>> graph['anuj']=[]
>>> graph['peggy']=[]
>>> graph['thom']=[]
>>> graph['jonny']=[]
>>> graph
{'you': ['alice', 'bob', 'claire'], 'bob': ['anuj', 'peggy'], 'alice': ['peggy'], 'claire': ['thom', 'jonny'], 'anuj': [], 'peggy': [], 'thom': [], 'jonny': []}

  

键—值对的添加顺序不重要,因为散列表是无序的。

 

有向图(directed graph)

其中的关系是单向

无向图(undirected graph)

没有箭头,直接相连的节点互为邻居

 

实现算法

代码

from collections import deque  #使用函数deque来创建一个双端队列
graph={'you': ['alice', 'bob', 'claire'], 'bob': ['anuj', 'peggy'], 'alice': ['peggy'], 'claire': ['thom', 'jonny'], 'anuj': [], 'peggy': [], 'thom': [], 'jonny': []}
def search(name):
    search_queue=deque()
    search_queue+=graph[name]
    searched=[]                 #这个列表用于记录检查过的元素
    while search_queue:
        person=search_queue.popleft()
        if not person in searched:
            if person_is_seller(person):
                print(person,'is a mango seller!')
                return True
            else:
                search_queue+=graph[person]
                searched.append(person)
    return False

def person_is_seller(name):
    return name[-1]=='m'

search('you')

  

原理

  1. 创建一个队列,用于存储要检查的元素
  2. 从队列弹出第一个元素
  3. 检查这个元素,是否满足要求。
  4. 如果满足返回结果,否则将这个元素的所有邻居加入队列
  5. 回到第二步。继续检查这些邻居。
  6. 如果队列为空,就说明没有满足条件的元素

 

停止条件(满足其一):

  •   找到一个满足条件的元素
  •   队列变成空的,这意味队列的所有元素,都没有满足条件

 

 

运行时间

广度优先搜索的运行时间为O(V + E),其中V为顶点(vertice)数,E为边数

 

解析:

在整个图中搜索元素,就意味着将沿每条边前行(记住,边是从一个人到另一个人的箭头或连接),因此运行时间至少为O(边数)。

还使用了一个队列,其中包含要检查的每个元素。将一元素添加到队列需要的时间是固定的,

即为O(1),因此对每个元素都这样做需要的总时间为O(元素个数)。

 

 

扩展

  1. 是一种特殊的图,其中没有往后指的边。
  2. 如果任务A依赖于任务B,在列表中任务A就必须在任务B后面。这被称为拓扑排序,使用它可根据图创建一个有序列表。

 

小结

  •   广度优先搜索指出是否有从A到B的路径。
  •   如果有,广度优先搜索将找出最短路径。
  •   面临类似于寻找最短路径的问题时,可尝试使用图来建立模型再使用广度优先搜索解决问题。
  •   有向图中的边为箭头,箭头的方向指定了关系的方向,例如, rama→adit表示rama欠adit钱。
  •   无向图中的边不带箭头,其中的关系是双向的,例如, ross - rachel表示“ross与rachel约会,而rachel也与ross约会”。
  •   队列是先进先出( FIFO)的。
  •   栈是后进先出( LIFO)的。
  •   需要按加入顺序检查搜索列表中的元素,否则找到的就不是最短路径,因此搜索列表必须是队列
  •   对于检查过的元素,务必不要再去检查否则可能导致无限循环