DAY 4 广度优先搜索
Posted 要不一起做梦吧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DAY 4 广度优先搜索相关的知识,希望对你有一定的参考价值。
今天要讲的是广度优先搜索。在讲正题之前,先说一个小故事。
老吴和小鹿兴致勃勃地聊到了一起去日本旅游的计划,他们一起罗列了几个想去城市,并把终点站定在了奈良。罗列完城市之后,他们搜集了这几个城市之间的交通状况,如下图所示:
罗列完路线图之后,他们开始计算基本的旅行费用,算来算去,他们悲哀地发现他们的钱包厚度不足以支持他们玩遍图中的城市,因为住宿和交通费可不是一笔小数目。
为此他们决定选择一条从上海到奈良的最短路线。
ok,现在轮到广度优先搜索上场了。(其实看一下也能看出最短路线,我们就当看不出来吧)
在广度优先搜索出场之前我们先来介绍一下它。
广度优先搜索是图算法的一种,广度优先搜索可以解决两种问题:
1.从A到B的最短路径
2.从A出发能到达B吗?
但是,广度优先搜索有进行的前提,那就是先要有一张像上面展示的一张线路图,那么怎么才能让计算机识别出一张图呢?
答案是使用散列表。
散列表可以明确的表示节点之间的联通关系。(python中的散列表即字典)
例如,用散列表表示东京所能到达的城市。
graph = {}
graph['Tokyo'] = ['Shanghai','Yokohama','Nagoya','Osaka','Kyoto']
那么,按照上面的例子,我们把整个路线图表示出来
代码如下:
#创建图
graph = {}
graph['Shanghai'] = ['Tokyo']
graph['Tokyo'] = ['Shanghai','Yokohama','Nagoya','Osaka','Kyoto']
graph['Yokohama'] = ['Tokyo']
graph['Nagoya'] = ['Tokyo','Yokohama','Osaka','Kyoto']
graph['Osaka'] = ['Tokyo','Nagoya','Kyoto','Nara']
graph['Kyoto'] = ['Tokyo','Osaka']
graph['Nara'] = ['Kyoto']
创建完成了线路图,那么现在开始说一说广度优先搜索的原理了,广度优先搜索每次只读取一个地名,如果这个地名不是我们要找的目标,那么广度优先搜索会寻找下一个地名,直到找到目标地名,或者所有的地名全部遍历。
为了确保能够有顺序地遍历,我们要用到队列这个数据结构。队列是一种先进先出的数据结构,只有入列和出列两种操作。
#导入双向对列
from collections import deque
当第一个地名不是我们的目标的时候,该地名从队列中出列,该地名所能到达的地名入列。这里就要注意一个问题,出列了的地名不能再次入列,否则像东京和名古屋这样能够相互达到,两个地名不断出列,入列就会导致死循环。那么我们在进行广度优先搜索的时候要注意对不能让地名重复入列。这一点我们只要创建一个已经搜索过的列表,只要不在列表中的地名就可以进行广度优先搜索。
根据这个思路我们写出如下代码
#实现广度优先搜索
def search(point,end):
search_queue = deque()
search_queue += graph[point]
searched = []
'''判断目前搜索的地名是否已经搜素过
如果没有搜索过,那么查看是否是目的地
'''
while search_queue:
current = search_queue.popleft()
if current not in searched:
if current == end:
print END!
else:
searched.append(current)
search_queue += graph[current]
return False
但是做到这样还不够,我们还需要知道最短的路径怎么走。那么我们要从已经找过的地名里,通过目的地来回退出整个路线。
代码如下
def findlastlocation(current,queue):
for i in queue:
if current in graph[i]:
return i
return None
那么也要更改广度优先搜索的代码
完整的代码如下:
# -*- coding:utf-8 -*-
#导入双向对列
from collections import deque
#创建图
graph = {}
graph['Shanghai'] = ['Tokyo']
graph['Tokyo'] = ['Shanghai','Yokohama','Nagoya','Osaka','Kyoto']
graph['Yokohama'] = ['Tokyo']
graph['Nagoya'] = ['Tokyo','Yokohama','Osaka','Kyoto']
graph['Osaka'] = ['Tokyo','Nagoya','Kyoto','Nara']
graph['Kyoto'] = ['Tokyo','Osaka']
graph['Nara'] = ['Kyoto']
#实现寻找上个地点名称的函数
'''
输入当前的位置,以及已查找过的队列
遍历已经查找过的对列
如果当前位置在索引元素的图中 那么索引元素就是上一个位置 返回该元素
如果没找到就返回None
'''
def findlastlocation(current,queue):
for i in queue:
if current in graph[i]:
return i
return None
#实现广度优先搜索
def search(point,end):
search_queue = deque()
search_queue += graph[point]
searched = []
#创建路线列表,在路线列表中先添加终点
routes = [end]
last_location = ''
'''判断目前搜索的地名是否已经搜素过
如果没有搜索过,那么查看是否是目的地
'''
while search_queue:
current = search_queue.popleft()
if current not in searched:
if current == end:
#先找到上一个位置
last_location = findlastlocation(current,searched)
#通过递归,找到整个路线
while last_location != 'Shanghai':
routes.append(last_location)
current = last_location
last_location = findlastlocation(current,searched)
routes.append(point)
return routes
else:
searched.append(current)
search_queue += graph[current]
return False
def print_routes(routes):
routes.reverse()
for place in routes:
print (place)
最后进行测试,找出最短路径:
print print_routes(search('Shanghai','Nara'))
ok!老吴和小鹿终于可以松一口气了。=)
(END)
以上是关于DAY 4 广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章