小白的算法初识课堂(part6)--广度优先搜索
学习笔记
学习书目:《算法图解》- Aditya Bhargava
文章目录
- 图简介
- 图是啥
- 广度优先搜索
- 寻找最短路径
- 队列
- 实现图
- 实现算法
- 运行时间
图简介
今天是五一,假如我要从家出发去公园玩,现在可去公园的公交车路线如下:
现在,我想找一条换乘最少的线路,该使用什么样的算法呢?
我们先找出一步就能到达的地方,显而易见,一步能到达A、B;再找出两步能到达的地方,经过简单寻找,我们发现两步能到达E、D、C三个地;第三步呢?可以看出第三步可以到达公园和E。很好!此时我们就找到了换乘最少的路线:家–1-->路–>A–3路–>E–5路–>公园
这种问题被称为最短路径问题。我们要找出最短路径,这可能是前往朋友家的最短路径,也可能是国际象棋中把对方将死的最少步数。解决最短路径问题的算法被称为广度优先搜索。
我们解决这个问题时,用了两个步骤:
(1)使用图来建立问题模型
(2)使用广度优先搜索解决问题
图是啥
图模拟了一组连接,比如可像下图一样表示小黄欠我钱:
我们再看一幅更复杂的图:
可以看到这幅图由节点和边组成,一个节点可能与众多节点直接相连,这些节点被称为邻居。比如,我是小黄的邻居,但奶奶不是小黄的邻居;奶奶既是我的邻居,又是大白的邻居;但是,奶奶没有邻居,因为虽然有指向她的箭头,却没有从她出发的箭头。这种图叫做有向图,其中的关系是单向的。无向图则没有箭头,直接相连的节点互为邻居。
我们看到,下面两个图是等价的:
广度优先搜索
广度优先搜索是一种用于图的查找算法,可帮助回答两类问题。
第一类问题:从节点A出发,有前往节点B的路径吗?
第二类问题:从节点A出发,前往节点B的哪条路径最短?
假如我是一位作者,我想在我的Twitter的朋友列表里找一位编辑。我的想法很简单,先在朋友里找有没有编辑,没有的话就在朋友的朋友里寻找,再没有的话,就在朋友的朋友的朋友里寻找…以此类推
现在我有3个朋友:
我先创建一个朋友名单:
['Huang', 'Hei', 'Bai']
然后依次检查我的3个朋友是否是编辑。假如我没有朋友是编辑,那么我就必须在朋友的朋友中寻找:
比如,我发现Huang不是编辑,那我就把它的朋友Write和Tim加入我的朋友名单,并把Huang从名单中剔除:
['Hei', 'Bai', 'Write', 'Tim']
使用这种算法将搜遍我的整个人际关系网,直到找到编辑。这就是广度优先搜索算法。
寻找最短路径
由我在Twitter的朋友列表里找编辑的例子中,我们已经回答了广度优先搜索的第一个问题(从节点A出发,有前往节点B的路径吗?)现在,我们就要回答第二个问题,即哪位编辑是离我关系最近。比如,我的朋友和我是一度关系,我朋友的朋友和我是二度关系。在我看来,一度关系胜过二度关系。因此,我要现在一度关系中寻找编辑,没有的话,再从二度关系中寻找编辑,以此类推。
需要注意的是,我们必须把一度关系查找完,才能查找二度关系。比如,我必须先查找完Huang, Hei, Bai才能查找Write等二度关系。
以我们刚刚建立的朋友名单为例,一度关系在二度关系之前加入名单:
['Hei', 'Bai',' Write', 'Tim']
我们按顺序依次检查名单中的每个人,看看他是否是编辑。这将先在一度关系中查找,再在二度关系中查找,因此找到的是关系最近的编辑。
注意!只有按顺序查找才能找到与我关系最近的编辑。换句话说Bai先于Tim加入名单,就要先检查Bai。有一个可实现这种目的的数据结构,那就是队列。
队列
队列类似于栈,你不能随机地访问队列中的元素。队列只支持两种操作:入队和出队。如果我将A和B加入队列,先加入队列的A也将先出队,而后加入的B则会后出队。
队列是一种先进先出(First In First Out,FIFO)的数据结构,而栈是一种后进先出(Last In First Out,LIFO)的数据结构。
实现图
现在,我们将用散列表来表达这种我-->Huang
的关系,并用python代码来实现图:
graph = {}
graph['me'] = ['Huang', 'Hei', 'Bai']
graph['Huang'] = ['Write', 'Tim']
graph['Bai'] = ['Tim']
graph['Hei'] = ['Black', 'Ada']
graph['Write'] = []
graph['Tim'] = []
graph['Black'] = []
graph['Ada'] = []
我们看到Write、Tim、Black、Ada没有邻居,因为只有指向它们的箭头,却没有从它们出发的箭头。
实现算法
python代码:
from collections import deque#判断谁是编辑
def person_is_edit(name):return name[-1] == 'a'#假设名字最后一个字母是a就是编辑#查找某人的关系列表中谁是编辑
def search(name):search_queue = deque()search_queue += graph[name]searched = []#记录已经检查过的人,防止低效率和无限循环while search_queue:person = search_queue.popleft()if person not in searched:if person_is_edit(person):print('I find you {}!'.format(person))return Trueelse:search_queue += graph[person]searched.append(person)return Falsesearch('me')
控制台输出:
I find you Ada!
我们看到,我们在上面的python代码中加入了一个已搜索名单searched,这是为了防止循环和低效率。比如,Huang和Bai都有一个朋友Tim,但是我们只需要检查一次Tim,否则重复查询就是做了无用功。
并且如果出现下面这种情况,我们就会进入死循环:
所以,在检查一个人是否是编辑之前,确认此人是否被检查过,就十分重要了。
运行时间
如果我在我的关系网中搜寻编辑,那就意味着我沿着每条边前行,因此运行时间至少是O(边数)。这里,我们还使用了一个队列,其中包含要检查的每个人。将一个人添加到队列需要的时间是固定的,即为O(1),因此对每个人都这样做需要的总时间为O(人数)。所以,广度优先搜索的运行时间为O(人数 + 边数),这通常写作O(V + E),其中V 为顶点数,E 为边数。
小白的算法初识课堂(part6)--广度优先搜索相关推荐
- 小白的算法初识课堂(part7)--狄克斯特拉算法
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 狄克斯特拉算法 具体步骤实现 术语 跳蚤市场 具体步骤实现 负权边 python实现 狄克斯特拉算法 在上一个 ...
- 小白的算法初识课堂(part9)--SHA及Simhash算法
学习笔记 学习书目:<算法图解>- Aditya Bhargava 安全散列算法(SHA) 在学SHA算法之前,我们先回顾一下前几个Blog所学的散列函数. 散列函数是这样的一个函数,即无 ...
- 小白的算法初识课堂(part8)--贪婪算法
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 教室调度问题 集合覆盖问题 近似算法 代码实现 NP完全问题 教室调度问题 假如我是一个学校的校长,我们学校有 ...
- 小白的算法初识课堂(part5)--散列表
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 散列函数 防止重复 冲突 性能 填装因子 散列函数 散列函数是这样的一个函数,即无论你给它什么样的数据,它都还 ...
- 小白的算法初识课堂(part4)--快速排序
学习笔记 学习书目:<算法图解>- Aditya Bhargava 分而治之 在这里,我想通过2个例子介绍一种著名的递归式问题解决方法–分而治之(D&C) 分蛋糕 假如,我要分一块 ...
- 小白的算法初识课堂(part3)--递归
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 递归 基线条件和递归条件 栈 调用栈 递归调用栈 递归 首先,我们看一段代码: def print_num(m ...
- 小白的算法初识课堂(part2)--选择排序
学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 选择排序 内存工作原理 数组 链表 读取 索引 插入 删除 是常见的数组和链表操作的运行时间 选择排序 pyt ...
- 小白的算法初识课堂(part1)--二分查找法
学习笔记 学习书目:<算法图解>- Aditya Bhargava 二分查找法 算法是一组完成任务的指令,任何代码片段都可视为算法.二分查找是一种算法,其输入是一个有序的元素列表(必须有序 ...
- 算法简介:层层递进----广度优先搜索(BFS)
算法简介:层层递进----广度优先搜索(BFS) 算法简介 算法简介 BFS算法思想: 首先以一个未被访问过的顶点作为起始顶点,访问其所有相邻的顶点,然后对每个相邻的顶点,再访问它们相邻的未被访问过的 ...
最新文章
- chsop 兼容jquery(解决与transport.js冲突)
- 【bzoj2751】[HAOI2012]容易题(easy) 数论,简单题
- 「PKUWC2018」Minimax
- 随机生成100万个数,排序后保存在文件中
- 利用 sys.sysprocesses 检查 Sql Server的阻塞和死锁
- 透露|Java学习的最后一点小秘密
- 如何快速实现移动端短视频功能?
- 创作一个数字人,总共分几步?(下)
- One year ago begininginginginging!
- qt designer 自定义插件找不到指定的模块_go与qt的新酒老瓶
- struts2漏洞修复
- CentOS配置DHCP服务器
- 凸透镜成像实验软件_凸透镜成像6道例题(含详答)
- 文章下载:关于窗宽窗位调节非常有用的论文《DICOM 医学图像窗口变换的加速算法》...
- 大地高、正高和正常高及高程异常
- RFID-Si24R1芯片基于Android 4.4平台的kernel驱动
- PS 将图片渐变透明
- window的mysql开机自动启动
- Unity开发 Photon Pun 多人游戏组件
- Java IO中涉及到的哪些类以及哪些设计模式
热门文章
- 机器学习——决策树的三种学习方法
- cron 12点执行_Linux中得循环调度任务执行
- php调用linux摄像头,Linux_在Linux操作系统上使用摄像头,我的公家笔记本的摄像头一直 - phpStudy...
- Runnable和Thread基础---多线程学习笔记(二)
- SpringBoot入门:新一代Java模板引擎Thymeleaf(理论)
- 不止性能优化,移动端 APM 产品研发技能
- junit No tests found matching Method
- SecureCRT登陆Centos 6.4乱码问题
- 超级详细的教程 一步步教你Vue项目中使用axios如何进行参数拼接
- 机房系统(三)——【充值 退卡 】