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 广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章

深度优先搜索法和广度优先搜索法

关于有向图的广度优先搜索

广度优先搜索BFS和深度优先搜索DFS

图的搜索4.2-广度优先搜索

搜索算法---广度优先搜索

搜索算法---广度优先搜索