算法——广度优先搜索
Posted 代码综合征
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法——广度优先搜索相关的知识,希望对你有一定的参考价值。
本文介绍图以及与图相关的算法——广度优先搜索。
广度优先搜索能让你找出两样东西之间最短的距离,但是最短距离可以有多重含义,如国际跳棋,计算走多少步就可以获胜。
图简介
要求从一地前往另一点的最短路径,称为最短路径问题。解决最短路径问题的算法被称为广度优先搜索。
图是一组连接的模拟,图由节点和边组成。一个节点可能与众多节点相连,这些节点被称为邻居。
也就是图用于模拟不同的东西是如何相连的。
广度优先搜索
关于图有两类问题,一类是从节点A出发,有前往节点B的路径吗?第二类是从节点A触发,前往节点B的哪条路径最短?
例如一个人的关系网,朋友是一度关系,朋友的朋友是二度关系。
广度优先算法是先在一度关系里搜索,再在二度关系里搜索,在广度优先搜索的执行中,搜索范围从起点开始逐渐向外延伸。
也可以这样看,一度关系在二度关系之前加入查找名单,那么有一种数据结构能够支持这个目的,那就是队列。
队列
队列支持两种操作,入队和出队。队列是一种先进先出的数据结构,而栈是一种后进先出的结构。
图的每个节点都与邻近点相连,如何表示“你->Bob”这样的关系?可以使用散列表,在python中就是dict。
比如,表示我与其他相连的关系,可以这么写:
graph = {}
graph["you"] = ["alice", "bob", "claire"]
在字典中间,一个key映射了一个数组,包含了所有的邻居。对于更大更复杂的图,则可以把每一个节点的邻居列出来。如:
graph = {}
graph["you"] = ["alice", "bob", "claire"]
graph["bob"] = ["anuj", "peggy"]
graph["alice"] = ["peggy"]
graph["claire"] = ["thom", "jonny"]
graph["anuj"] = []
graph["peggy"] = []
graph["thom"] = []
graph["jonny"] = []
键值对的添加顺序没有影响,因为散列表是无序的。
在上面的例子中,有的节点没有邻居,这是因为这是一个有向图,其中的关系是单向的。而对于无向图,直接相连的节点互为邻居。
实现算法
首先创建一个队列,在python中可以使用deque来创建一个双端队列。
from collections import deque
search_queue = deque()
search_queue += graph["you"]
while search_queue:
person = search_queue.popleft()
if person_is_seller(person):
print person + " is a mango seller!"
return True
else:
search_queue += graph[person]
return False
def person_is_seller(name):
return name[-1] == 'm' #只是一个判断的示例
这个算法将被不断执行,直到找到一个结果,或者队列变成空。
不过这个算法还有个问题,就是如果检查一个元素前,必须确认之前是没有检查过的。因为如果一个元素能够多次检查,可能会造成无限循环。
最后广度优先算法的代码为:
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
运行时间
搜索图的时候,意味着将沿着每条边进行,因此运行时间至少为 O(边数)
,
同时还使用了队列,包含要检查的每个节点,讲一个节点添加到队列所需时间是固定的,为O(1),因此对每个人都这么做的总时间为 O(人数)
。
所以广度优先的运行时间就是 O(节点数+边数)
,也就是 O(V+E)
,V是顶点数,E为边数。
小结
广度优先搜索指出是否有从A到B的路径。
如果有,广度优先搜索将找出最短路径。
面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来 解决问题。
有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱。
无向图中的边不带箭头,其中的关系是双向的,例如,ross - rachel表示“ross与rachel约 会,而rachel也与ross约会”。
队列是先进先出(FIFO)的。
栈是后进先出(LIFO)的。
你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必 须是队列。
对于检查过的人,务必不要再去检查,否则可能导致无限循环。
以上是关于算法——广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章