广度优先搜索是一种图算法。
图简介
图模拟一组连接。图由节点和边组成。一个节点可能与众多节点直接相连,这些节点被称为邻居。图用于模拟不同的东西时如何相连的。
有向图:如果某个节点有指向他们的箭头,但没有从他们出发指向其他人的箭头,这被称为有向图。
无向图:没有箭头,直接相连的节点互为邻居。
广度优先搜索简介
广度优先搜索是一种用于图的查找算法,可帮助解决两类问题:
第一类问题:从节点A出发,有前往节点B的路径吗?
第二类问题:从节点A出发,前往节点B的哪条路径最短?
队列
广度优先搜索需要按照顺序查找,有一种可实现这种目的的数据结构,队列。队列支持两种操作:入队和出队,且遵循先进先出(First In First Out,FIFO)。
实现图
from collections import deque
import sys
# 在你的朋友和朋友的朋友中寻找芒果经销商(姓名是否以m结尾,如果是,他就是芒果经销商)
# 判断一个人是不是芒果经销商
def person_is_seller(name):
return name[-1] == 'm'
# 寻找函数
def search(name):
# 创建一个队列
search_queue = deque()
# 将你的邻居都加入到这个搜索队列中
search_queue += graph[name]
# 这个数组用于记录检查过的人
searched = []
# While循环查找芒果经销商
while search_queue: # 只要队列不空
person = search_queue.popleft() # 取出其中的第一个人
if person not in searched: # 仅当这个人没检查过时才检查
if person_is_seller(person): # 检查这个人是否是芒果经销商
print(person + " is a mango seller!") # 是芒果经销商,并输出
sys.exit(0) # 退出程序
else:
search_queue += graph[person] # 不是芒果经销商,将这个人的朋友都加入搜素队列
searched.append(person) # 将这个人标记为检查过
# 如果到达这里,就说明队列中没人是芒果经销商
print("No person is a mango seller!")
# 主函数
if __name__ == '__main__':
# 创建邻居列表
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"] = []
search("you")
实现结果
运行时间
在以上芒果经销商寻找案例中,广度优先搜索的运行时间为O(人数+边数),即O(V+E),其中V为顶点数,E为边数。
小结
1.广度优先搜索指出是否有从A到B的途径
2.如果有,广度优先搜索将找出最短路径
3.面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题
4.有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama->adit表示rama欠adit钱
5.无向图中的边不带箭头,其中的关系是双向的。
6.队列是先进先出(FIFO)的
7.栈是后进先出的(LIFO)的
8.你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必须是队列
9.对于检查过的人,务必不要再去检查,否则可能导致无限循环