笔记:《算法图解》第六章:图、队列、广度优先搜索

1.图

模拟一组连接。用于模拟不同的东西是如何相连的。图由节点(node)和(edge)组成。一个节点可能与众多节点直接相连,这些节点被称为邻居。
是一种特殊的图,所有的边都往前指,没有往后指的边。树的根节点(入度为0)只有一个,且所有子节点只能有一个父节点(入度为1)。

2.队列

队列类似于栈,你不能随机地访问队列中的元素。队列只支持两种操作:入队和出队。

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

3.广度优先搜索

解决最短路径问题的算法被称为广度优先搜索。
面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题。
广度优先搜索是一种用于图的查找算法,可帮助回答两类问题。

第一类问题:是否有从节点A到节点B的路径?
假设你经营着一个芒果农场,需要寻找芒果销售商,以便将芒果卖给他。你想知道在Facebook,你与芒果销售商有联系吗?为此,你可在朋友中查找。
这种查找很简单。首先,创建一个朋友名单。
然后,依次检查名单中的每个人,看看他是否是芒果销售商。
假设你没有朋友是芒果销售商,那么你就必须在朋友的朋友中查找。
检查名单中的每个人时,你都将其朋友加入名单。
这样一来,你不仅在朋友中查找,还在朋友的朋友中查找。别忘了,你的目标是在你的人际关系网中找到一位芒果销售商。因此,如果Alice不是芒果销售商,就将其朋友也加入到名单中。这意味着你将在她的朋友、朋友的朋友等中查找。使用这种算法将搜遍你的整个人际关系网,直到找到芒果销售商。这就是广度优先搜索算法。
第二类问题:如果有,从节点A出发,前往节点B的哪条路径最短?
刚才你看到了如何回答第一类问题,下面来尝试回答——谁是关系最近的芒果销售商。例如,朋友是一度关系,朋友的朋友是二度关系。
在你看来,一度关系胜过二度关系,二度关系胜过三度关系,以此类推。因此,你应先在一度关系中搜索,确定其中没有芒果销售商后,才在二度关系中搜索。广度优先搜索就是这样做的!在广度优先搜索的执行过程中,搜索范围从起点开始逐渐向外延伸,即先检查一度关系,再检查二度关系。一度关系在二度关系之前加入查找名单。你按顺序依次检查名单中的每个人,看看他是否是芒果销售商。这将先在一度关系中查找,再在二度关系中查找,因此找到的是关系最近的芒果销售商。广度优先搜索不仅查找从A到B的路径,而且找到的是最短的路径。

注意,只有按添加顺序查找时,才能实现这样的目的。因此,你需要按添加顺序进行检查。有一个可实现这种目的的数据结构,那就是队列(queue)。

4.实现图算法

一般利用散列表的映射关系实现图。
散列表是无序的,因此添加键—值对的顺序无关紧要。

工作原理:
在这里插入图片描述
Python算法:

from collections import deque
graph = {}
graph["you"] = ["alice", "bob", "claire"]
graph["bob"] = ["anuj", "peggy"]
graph["alice"] = ["peggy"]
graph["claire"] = ["thom", "jonny"]
graph["anuj"] = []
graph["peggy"] = []
graph["thom"] = []
graph["jonny"] = []
def person_is_seller(name):
	'''判断一个人是否是经销商,检查人的姓名是否以m结尾:如果是,他就是芒果销售商。'''
	return name[-1] == 'm'
def search(name):
    search_queue = deque()
    search_queue += graph[name]
    # This array is how you keep track of which people you've searched before.
    searched = []
    while search_queue:
        person = search_queue.popleft()
        # Only search this person if you haven't already searched them.
        if person not in searched:
            if person_is_seller(person):
                print(person + " is a mango seller!")
                return True
            else:
                search_queue += graph[person]
                # Marks this person as searched
                searched.append(person)
    return False

search("you")

❑ 你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必须是队列。
❑ 对于检查过的人,务必不要再去检查,否则可能导致无限循环。
算法运行时间:
如果你在你的整个人际关系网中搜索芒果销售商,就意味着你将沿每条边前行(记住,边是从一个人到另一个人的箭头或连接),因此运行时间至少为O(边数)。
你还使用了一个队列,其中包含要检查的每个人。将一个人添加到队列需要的时间是固定的,即为O(1),因此对每个人都这样做需要的总时间为O(人数)。所以,广度优先搜索的运行时间为O(人数+边数),这通常写作O(V+E),其中V为顶点(vertice)数,E为边数。

练习

6.1 找出从起点到终点的最短路径的长度。
在这里插入图片描述
6.2 找出从cab到bat的最短路径的长度。
在这里插入图片描述
6.3 下面的小图说明了我早晨起床后要做的事情。
在这里插入图片描述
该图指出,我不能没刷牙就吃早餐,因此“吃早餐”依赖于“刷牙”。另一方面,洗澡不依赖于刷牙,因为我可以先洗澡再刷牙。根据这个图,可创建一个列表,指出我需要按什么顺序完成早晨起床后要做的事情:(1) 起床(2) 洗澡(3) 刷牙(4) 吃早餐请注意,“洗澡”可随便移动,因此下面的列表也可行:(1) 起床(2) 刷牙(3) 洗澡(4) 吃早餐
请问下面的三个列表哪些可行、哪些不可行?
在这里插入图片描述

6.4 下面是一个更大的图,请根据它创建一个可行的列表。
在这里插入图片描述
从某种程度上说,这种列表是有序的。如果任务A依赖于任务B,在列表中任务A就必须在任务B后面。这被称为拓扑排序,使用它可根据图创建一个有序列表。假设你正在规划一场婚礼,并有一个很大的图,其中充斥着需要做的事情,但却不知道要从哪里开始。这时就可使用拓扑排序来创建一个有序的任务列表。

6.5 请问下面哪个图是树?
在这里插入图片描述

答案

6.1 最短路径的长度为2。
6.2 最短路径的长度为2。
6.3 A不可行,B可行,C不可行。
6.4 1——起床,2——锻炼,3——洗澡,4——刷牙,5——穿衣服,6——打包午餐,7——吃早餐。
6.5 A是树,B不是树,C是树。C是一棵横着的树。树是图的子集,因此树都是图,但图可能是树,也可能不是。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值