算法图解-广度优先算法

Introduction:

在基于图的操作中,如果需要统计A到B的最短路径,广度优先是比较合适的算法。

首先看图:

 

我们需要从You开始,从You的每一层关系开始查找,知道找到经销商开始。假设经销商是THOM?

这是一个有三层关系的图,其中You、BOB、ALICE是其中的节点,而You->ALICE这样的就是其中的边,这样对于You,他的关系有:

You->BOB,You->ALICE,You->CLAIRE,在Python中,使用散列表可以描述对应的关系。

表示这种映射关系的Python代码如下:

graph={}                                      #先创建一个散列表  或者使用 graph=dict()

graph["you"]=["ALICE","BOB",CIAIRE"]

使用Python表示完整的图:

graph={}                                      #先创建一个散列表  或者使用 graph=dict()

graph["you"]=["ALICE","BOB",CIAIRE"]

graph["BOB"]=["ANUJ","PUGGY"]

graph["ALICE"]=["PEGGY"]

graph["CLAIRE"]=["THOM","JONNY"]

graph["ANUJ"]=[]

graph["PEGGY"]=[]

graph["THOM"]=[]

graph["JONNY"]=[]

Tips:对于程序而言,键-值的添加顺序重要吗?比如使用graph["you"]=["BOB",CIAIRE"."ALICE"]会对结果产生影响吗?

Answer:因为散列表是无序的,换言之键值对的顺序也是无序的,所以对程序而言没有什么影响。

 

Achieve:

简单通过图片描述一下算法的工作原理:

直接放上书中的图:

在使用广度优先算法时,需要创建一个额外队列用于保存哪些节点被检索了,哪些没有,在python中,可以使用deque来创建一个双端队列,可以实现入队出队操作。

from collections import deque 

search_queue = deque ()                     #新建一个队列

search_queue += graph["You"]            #将You的三个邻居添加到队列里面

下面看看其他的代码

while search_queue:                                                                               #search_queue是一个队列,主要队列有数据就往下执行

          person = search_queue.popleft()                                                  #取出其中的一个人

          if person_is_seller(seller):                                                             #检查这个人是否是经销商

                    print person + "is a mango seller !"                                     #如果是,就打印  然后结束程序

                    return True

          else:

                    search_queue += graph [person]                                        #不是经销商,就把他的朋友都加入队列

return False                                                                                             #如果所有的都不是经销商,返回并退出

在上述的代码中,person_is_seller(name)是一个未定义的函数,咱们需要自己定义

def person_is_seller(name):

          return name== "THUM"

 

Tips:这个代码中有个问题,在上面的图中,PEGGY跟两个人有关系,所以如果使用上述代码,PEGGY会被重复检查,这样相当于做了无用功,在一个数据较多的程序中,我们需要避免这种情况的发生,我们可以:

创建一个已检索人的队列,每次检索这个人的时候,看一下已检索人队列是不是已经有这个人,如果有了就不需要检索了,如果没有,检查这个人,然后把这个人加到已检索人队列。

当然在这个例子中,我们已知了重复为一个,对于这个例子,每次检查避免重复带来的效益不是太高,不过这种检查的思想是需要具备的。

 

运行时间:

单从边数来讲,运行时间最多为O(边数)

但是我们还添加了另外一个队列,用来检索已经检查过的人,所以在队列中添加人的操作时间复杂度为O(1),因此添加人需要的总时间数为O(人数),两者结合起来,总的时间就是O(人数+边数),记作O(V+E),其中V为vertice。

 

Reflect:

1 在这个算法中,有什么可以优化的地方?

2 出了上述程序会重复检索这个不足之外,是否有其他的不足?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值