ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【算法】广度优先搜索——最短路径问题

2020-11-23 21:59:04  阅读:723  来源: 互联网

标签:经销商 检查 队列 最短 芒果 算法 person 搜索 广度


目录

1. 广度优先搜索

1.1 查找最短路径

1.2 队列

2. 算法实现

3. 运行时间


1. 广度优先搜索

广度优先搜索是一种用于图(图的介绍)的查找算法,可帮助回答两类问题。

  1. 第一类问题:从节点A出发,有前往节点B的路径吗?
  2. 第二类问题:从节点A出发,前往节点B的哪条路径最短?

当要计算地点A到地点B的最短路径时,你可以使用广度优先搜索。这个问题属于第二类问题:哪条路径最短?下面来详细研究这个算法,你将使用它来回答第一类问题:有路径吗?

假设你经营着一个芒果农场,需要寻找芒果经销商,以便将芒果卖给他。然而,你并不认识芒果经销商。为此,你可以在朋友中查找。

这种查找很简单。首先,创建一个朋友清单。

然后,一次检查名单中的每个人,看看他是否是芒果经销商。

假设你没有朋友是芒果经销商,那么你就必须在朋友的朋友中查找。

检查名单中的每个人时,你都将其朋友加入名单。

这样一来,不仅在朋友中查找,还在朋友的朋友中查找。别忘了,你的目标是在人际关系网中找到一位芒果经销商。因此,如果Alice不是芒果经销商,就将他的朋友也加入到名单中。这意味着你将她的朋友、朋友的朋友等中查找。使用这种算法将搜索你的整个人际关系网,直到找到芒果经销商。这就是广度优先搜索算法。

1.1 查找最短路径

再次重复,广度优先搜索可回答两类问题:

  1. 第一类问题:从节点A出发,有前往节点B的路径吗?
  2. 第二类问题:从节点A出发,前往节点B的哪条路径最短?

刚才你看到了如何回答第一类,下面来尝试回答第二类问题——谁是关系最近的芒果经销商。例如,朋友是一度关系,朋友的朋友是二度关系。

在你看来,一度关系胜过二度关系,二度关系胜过三度关系,以此类推。因此,你应先在一度搜索中搜索,确定没有芒果经销商后,才在二度关系中搜索。广度优先搜索就是这样做的!在广度优先搜索的执行过程中,搜索范围从起点开始逐渐向外延伸,即先检查一度关系,再检查二度关系。顺便问一句:将先检查Claire还是Anuj呢? Claire是一度关系,而Anuj是二度关系,因此将先检查Claire,后检查Anuj。

你也可以这样看,一度关系在二度关系之前加入查找名单。

你按顺序依次检查名单中的每个人,看看他是否是芒果经销商。这将先在一度关系中查找,再在二度关系中查找,因此找到的是关系最近的芒果经销商。广度优先搜索不仅查找从A到B的路径,而且找到的是最短的路径。

注意,只有按添加顺序查找时,才能实现这样的目的。换句话说,如果Claire先于Anuj加入名单就需要先检查Claire,再检查Anuj。如果Claire和Anuj都是芒果经销商,而你先检查Anuj再检查Claire,结果将会如何呢?中安到的芒果经销商并非是与你关系最近的,因为Anuj是你朋友的朋友,而Claire是你的朋友。因此,你需要按添加顺序进行检查。有一个可实现这种目的的数据结构,那就是队列(queue)

1.2 队列

队列的工作原理与现实生活中的队列完全相同,假设你与朋友一起在公交车站排队,如果你排在他前面,你将先上车。队列的工作原理与此相同。队列类似于栈,你不能随机地访问队列中的元素。队列只支持两种操作:入队和出队

如果你将两个元素加入队列,先加入的元素将在后加入的元素之前出队。因此,你可使用队列来表示查找名单!这样,先加入的人将先出队并先被检查。

队列是一种先进先出(First In First Out, FIFO)的数据结构,而栈是一种后进先出(Last In First Out,LIFO)的数据结构。

知道队列的工作原理之后,即可实现广度优先搜索。

2. 算法实现

先概述一下这种算法:

首先,创建一个队列。在Python中,可使用函数deque来创建一个双端队列。

from collection import deque
search_queue = deque()    #创建一个队列
search_queue += graph["you"]    #将你的邻居都加入到这个搜索队列中

别忘了,graph["you"]是一个数组,其中包含你的所有邻居,如["alice", "bob", "claire"]。这些邻居都将加入到搜索队列中。

下面来看看其他的代码。

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    #如果达到了这里,就说明队列中没人是芒果经销商

最后,你还需要编写函数person_is_seller,判断一个人是否是芒果经销商。如下所示:

def person_is_seller(name):
    return name[-1] == 'm'

这个函数仅通过检查人的姓名是否是以m结尾:如果是,他就是芒果销售商。这种判断方法有点搞笑,但就这个示例而言是可行的。下面来看看广度优先搜索的执行过程。

这个算法将不断执行,直到满足以下条件之一:

  1. 找到一位芒果供应商;
  2. 队伍变成空的,这意味着你的人际关系网中没有芒果经销商。

Peggy既是Alice的朋友又是Bob的朋友,因此她将被加入队列两次:一次是在添加Alice的朋友时,另一次是在添加Bob的朋友时。因此,搜索队列将包含两个Peggy。

但你只需要检查Peggy一次,看她是不是芒果经销商。如果你检查两次,就做了无用功。因此,检查完一个人后,应将其标记为已检查,且不再检查他。

如果不这样做,就可能会导致无限循环,假设你的人际关系网类似于下面这样。

一开始,搜索队列包含你的所有邻居。

现在你检查Peggy。他不是芒果经销商,因此你将其所有邻居都加入搜索队列。

接下来,你检查自己。你不是芒果经销商,因此你将你所有的邻居都加入到搜索队列。

以此类推,将形成无限循环,因此搜索队列将在包含你和包含Peggy之间反复切换。

检查一个人之前,要确认之前没检查过他,这很重要。为此,你可使用一个列表来记录检查过的人。

考虑到这一点后,广度优先搜索的最终代码如下:

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


search("you")

3. 运行时间

如果你在你的整个人际关系网中搜索芒果销售商,就意味着你将沿每条边前进(记住,边是一个人到另一个人的箭头或连接),因此运行时间至少为O(边数)。

你还使用了一个队列,其中包含要检查的每个人,将一个人添加到队列需要的时间固定的,即为O(1),因此对每个人都需要的总时间为O(人数)。所以,广度优先搜索的运行时间为O(人数+边数),这通常写作O(V+E),其中V为顶点(vertice)数,E为边数。

 

 

标签:经销商,检查,队列,最短,芒果,算法,person,搜索,广度
来源: https://blog.csdn.net/weixin_46318945/article/details/110001201

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有