图和广度优先搜索的基本概念
图模拟一组连接,根据连接的线段有方向和无方向分为有向图和无向图。
图由节点和边组成。一个节点可能与众多节点直接相连,这样直接相连的节点称为邻居。
而广度优先搜索,简称BFS,是从根节点开始,沿着树的宽度(广度)遍历树的节点,如果发现目标,则演算终止。
所以,你需要建立一个人际关系图,其中有一度朋友关系,二度朋友关系等等,其中一度朋友关系大于二度朋友关系,依此类推。
当你冥思苦想加上打电话询问你的朋友都有哪些朋友之后,你终于建立好了这张人际关系图。
此时,你肯定是首先在所有一度朋友关系的人里面搜索,看看有没有卖房子的,如果有,OK直接找他了;如果没有,再去找二度朋友关系(朋友的朋友)的人;如果再没有再去找三度朋友关系的人;依此类推。
上面这种思路就是广度优先搜索!
广度优先搜索可解决的问题:
- 从节点A出发,有前往节点B的路径吗?
- 从节点A出发,前往B的哪条路径最短?
算法实现
要达到目的,只有添加顺序查找,才能达到目的。即,只有先添加你的朋友,把你的朋友查询完后,在添加你朋友的朋友,将你朋友的朋友查询完后,在添加朋友的朋友的朋友,以此类推。有一个可实现这种目的的数据结构,那就是队列。
- 队列是一种先进先出(Fist In Fist Out)的数据结构,而栈是一种后进先出的数据结构。
你和你的朋友们的关系以及他们的朋友关系,可以用散列表来表示。散列表可以使键映射到值,在这里,要将节点映射到所有的朋友,例如:
graph = {}
graph["you"] = ["alice", "bob", "claire"]
“你”被映射到了一个数组,因此graph["you"]是一个数组,其中包含了“你”的所有朋友。
完整的朋友关系散列图代码:
graph = {}
graph["you"] = ["alice", "bob", "claire"] #对应的值为一个数组
graph["bob"] = ["peggy", "anuj"]
graph["peggy"] = []
graph["anuj"] = []
graph["alice"] = ["peggy"]
graph["claire"] = ["thon", "jonnym"]
graph["thon"] = []
graph["jonny"] = []
要注意的是,添加关系时的前后顺序不影响结果,因为散列图时无序的,因此添加 键-值对的顺序无关紧要。
现在关系图已经建立好了,那么接下来就是实现找 卖房子的 人了。
from collections import deque
def person_is_seller(name):
return name[-1] == "m" #检查人的姓名是否以m结尾,有点草率0.0
def search(name):
search_queue = deque()
search_queue += graph[name]
searched = [] #这个数组用于记录检查过的人
while search_queue:
person = search_queue.popleft()
if person not in searched: #这个人没有检查时才检查
if person_is_seller(person):
print (person)
return True
else:
search_queue += graph[person]
searched.append(person) #将这个人标记为已检查
return False
第一个if语句的必要性。存在这样的一种情况,A的朋友时B,B的朋友是A。那么就会陷入无限循环。