数据结构-深度优先遍历和广度优先遍历(漫画)
————— 第二天 —————
————————————
什么是 深度/广度 优先遍历?
深度优先遍历简称DFS(Depth First Search),广度优先遍历简称BFS(Breadth First Search),它们是遍历图当中所有顶点的两种方式。
这两种遍历方式有什么不同呢?我们来举个栗子:
我们来到一个游乐场,游乐场里有11个景点。我们从景点0开始,要玩遍游乐场的所有景点,可以有什么样的游玩次序呢?
第一种是一头扎到底的玩法。我们选择一条支路,尽可能不断地深入,如果遇到死路就往回退,回退过程中如果遇到没探索过的支路,就进入该支路继续深入。
在图中,我们首先选择景点1的这条路,继续深入到景点7、景点8,终于发现走不动了(景点旁边的数字代表探索次序):
于是,我们退回到景点7,然后探索景点10,又走到了死胡同。于是,退回到景点1,探索景点9:
按照这个思路,我们再退回到景点0,后续依次探索景点2、3、5、4、6,终于玩遍了整个游乐场:
像这样先深入探索,走到头再回退寻找其他出路的遍历方式,就叫做深度优先遍历(DFS)。
除了像深度优先遍历这样一头扎到底的玩法以外,我们还有另一种玩法:首先把起点相邻的几个景点玩遍,然后去玩距离起点稍远一些(隔一层)的景点,然后再去玩距离起点更远一些(隔两层)的景点......
在图中,我们首先探索景点0的相邻景点1、2、3、4:
接着,我们探索与景点0相隔一层的景点7、9、5、6:
最后,我们探索与景点0相隔两层的景点8、10:
像这样一层一层由内而外的遍历方式,就叫做广度优先遍历(BFS)。
深度/广度优先遍历 的实现
深度优先遍历
首先说说深度优先遍历的实现过程。这里所说的回溯是什么意思呢?回溯顾名思义,就是自后向前,追溯曾经走过的路径。
我们把刚才游乐场的例子抽象成数据结构的图,假如我们依次访问了顶点0、1、7、8,发现无路可走了,这时候我们要从顶点8退回到顶点7。
而后我们探索了顶点10,又无路可走了,这时候我们要从顶点10退回到顶点7,再退回到顶点1。
像这样的自后向前追溯曾经访问过的路径,就叫做回溯。
要想实现回溯,可以利用栈的先入后出特性,也可以采用递归的方式(因为递归本身就是基于方法调用栈来实现)。
下面我们来演示一下具体实现过程。
首先访问顶点0、1、7、8,这四个顶点依次入栈,此时顶点8是栈顶:
从顶点8退回到顶点7,顶点8出栈:
接下来访问顶点10,顶点10入栈:
从顶点10退到顶点7,从顶点7退到顶点1,顶点10和顶点7出栈:
探索顶点9,顶点9入栈:
以此类推,利用这样一个临时栈来实现回溯,最终遍历完所有顶点。
广度优先遍历
接下来该说说广度优先遍历的实现过程了。刚才所说的重放是什么意思呢?似乎听起来和回溯差不多?其实,回溯与重放是完全相反的过程。
仍然以刚才的图为例,按照广度优先遍历的思想,我们首先遍历顶点0,然后遍历了邻近顶点1、2、3、4:
接下来我们要遍历更外围的顶点,可是如何找到这些更外围的顶点呢?我们需要把刚才遍历过的顶点1、2、3、4按顺序重新回顾一遍,从顶点1发现邻近的顶点7、9;从顶点3发现邻近的顶点5、6。
像这样把遍历过的顶点按照之前的遍历顺序重新回顾,就叫做重放。同样的,要实现重放也需要额外的存储空间,可以利用队列的先入先出特性来实现。
下面我们来演示一下具体实现过程。
首先遍历起点顶点0,顶点0入队:
接下来顶点0出队,遍历顶点0的邻近顶点1、2、3、4,并且把它们入队:
然后顶点1出队,遍历顶点1的邻近顶点7、9,并且把它们入队:
然后顶点2出队,没有新的顶点可入队:
以此类推,利用这样一个队列来实现重放,最终遍历完所有顶点。
- /**
- 图的顶点
- / private static class Vertex { int data; Vertex(int data) { this.data = data; } } /*
- 图(邻接表形式)
- / private static class Graph { private int size; private Vertex[] vertexes; private LinkedList adj[]; Graph(int size){ this.size = size; //初始化顶点和邻接矩阵 vertexes = new Vertex[size]; adj = new LinkedList[size]; for(int i=0; i*
- 深度优先遍历
- / public static void dfs(Graph graph, int start, boolean[] visited) { System.out.println(graph.vertexes[start].data); visited[start] = true; for(int index : graph.adj[start]){ if(!visited[index]){ dfs(graph, index, visited); } } } /*
- 广度优先遍历
- */
- public static void bfs(Graph graph, int start, boolean[] visited, LinkedList queue) {
- queue.offer(start);
- while (!queue.isEmpty()){
- int front = queue.poll();
- if(visited[front]){
- continue;
- }
- System.out.println(graph.vertexes[front].data);
- visited[front] = true;
- for(int index : graph.adj[front]){
- queue.offer(index);;
- }
- }
- }
- public static void main(String[] args) {
- Graph graph = new Graph(6);
- graph.adj[0].add(1);
- graph.adj[0].add(2);
- graph.adj[0].add(3);
- graph.adj[1].add(0);
- graph.adj[1].add(3);
- graph.adj[1].add(4);
- graph.adj[2].add(0);
- graph.adj[3].add(0);
- graph.adj[3].add(1);
- graph.adj[3].add(4);
- graph.adj[3].add(5);
- graph.adj[4].add(1);
- graph.adj[4].add(3);
- graph.adj[4].add(5);
- graph.adj[5].add(3);
- graph.adj[5].add(4);
- System.out.println("图的深度优先遍历:");
- dfs(graph, 0, new boolean[graph.size]);
- System.out.println("图的广度优先遍历:");
- bfs(graph, 0, new boolean[graph.size], new LinkedList());
- }
以上内容来自《漫画算法》
</div>
数据结构-深度优先遍历和广度优先遍历(漫画)相关推荐
- 数据结构之图:邻接矩阵和邻接表、深度优先遍历和广度优先遍历
简介 线性表是一种线性结构,除了头结点和尾节点,线性表的每个元素都只有一个前取节点和一个后继节点.而树结构则相较于线性表更加复杂,它描述的关系为数据元素之间的父子关系,也是现实世界父子关系的缩影, 一 ...
- 数据结构—无向图创建邻接矩阵、深度优先遍历和广度优先遍历(C语言版)
无向图创建邻接矩阵.深度优先遍历和广度优先遍历 一.概念解析: (1)无向图: (2)邻接矩阵: 二.创建邻接矩阵: 三.深度遍历.广度遍历 (1)深度遍历概念: (2)广度遍历概念: 四.实例展示 ...
- 大话数据结构 17:图的深度优先遍历和广度优先遍历
深度优先遍历 主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底-,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点 ...
- 二叉树的深度优先遍历和广度优先遍历
二叉树是一种很重要的数据结构,对于二叉树的遍历,有深度优先遍历和广度优先遍历,深度优先遍历又有先序.中序.后续遍历,广度优先遍历就是按层遍历. 1. 深度优先遍历 深度优先遍历,也就是先序.中序.后续 ...
- 图:图的邻接表创建、深度优先遍历和广度优先遍历代码实现
邻接表介绍 邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构比较较浪费存储空间.如果不想浪费存储空间,大家肯定会先到链表.需要空间的时候再才想内存去申请,同样适用于图 ...
- 图:图的邻接矩阵创建、深度优先遍历和广度优先遍历详解
邻接矩阵介绍 直接说,邻接矩阵是图的一种存储结构.那么图是什么呢?图是一种逻辑结构,和线性结构.树形结构.集合结构一样 是一种逻辑结构用来描述数据对象中的数据元素之间的关系.来看下图的定义:图(Gra ...
- 实现教材算法7.2利用邻接矩阵构造无向图的算法,在此基础上进行深度优先遍历和广度优先遍历。
软件学院实验报告 姓名: 学号: 专业: 年级: 课程名称 数据结构 实验名称 实验9.图的遍历 实验的准备阶段 实验内 ...
- 二叉树深度优先遍历和广度优先遍历
二叉树深度优先遍历和广度优先遍历
- 多级树的深度优先遍历与广度优先遍历(Java实现)
目录 多级树的深度优先遍历与广度优先遍历(Java实现) 节点模型 深度优先遍历 广度优先遍历 多级树的深度优先遍历与广度优先遍历(Java实现) 深度优先遍历与广度优先遍历其实是属于图算法的一种,多 ...
- 广度优先搜索生成树怎么画_图的深度优先遍历与广度优先遍历以及最小生成树...
图的深度优先遍历 题目:写出附从每个顶点出发的一次深度优先搜索遍历序列.在纸上画出遍历过程和序列,提交截图. 错误回答 从A点开始遍历:0124-01324-0134-0324-034 从B点开始遍历 ...
最新文章
- python时间日期字符串各种
- 使用sklearn自带公式计算余弦相似度
- Android调用蓝牙打印机
- 项目简单实用方式_组合替代继承_算法切换
- C++网络编程快速入门(二):Linux下使用select演示简单服务端程序
- mysql 有索引 不被使用方法_MySQL教程100-索引在什么情况下不会被使用?
- Android开发笔记(二十七)对象序列化
- python marshal 对象序列化和反序列化
- 计算机设置定时关机win10,Win10电脑如何设置定时关机?Win10电脑设置定时关机命令...
- 怎么把多个pdf文件合并成一个?
- Linux下套接字详解(八)----select模式下服务器(非阻塞,单进程+多进程+多线程)
- 判断天干,地支,生肖推算
- 一个登录页面的测试用例(借鉴他人的,方便查阅)
- oracle数据前面补0,Oracle 数字前面自动补0
- 计算机体检查杀病毒,如何去深度查杀电脑病毒
- 如何将图片压缩到指定大小?压缩图片大小的方法
- 判断是否为USD格式
- 诚挚邀请您注册并体验 wolai
- Linux系统中编译大型C语言项目必备技能之:Makefile文件的编写
- java与UML-1-工欲善其事必先利其器
热门文章
- 利用js实现table增加一行
- 两个整形变量,不用中间变量进行替换!
- PCL点云库学习(1):环境配置(Ubuntu16.04+QT5+VTK8.0)
- 2021-10-06
- 无法更改域名 php网页,WordPress更改新域名后网站无法正常运行怎么办?
- python包里面的dll是什么_Python中的包ImportError
- php多个 r n如何过滤,php怎么去掉r n
- 几步实现stm32上面移植mqtt
- 【重温基础】7.时间对象
- [LeetCode]k个一组翻转链表(Reverse Nodes in k-Group)