前言

图的遍历与前面文章中的二叉树遍历还是存在很大区别的。所谓图的遍历指的是从图中的某一个顶点出发访问图中的其余顶点,并且需要保证每个顶点只被访问一次。由于图比二叉树复杂得多,所以前面二叉树的遍历算法在图中是行不通的。因为对于任意一个顶点来讲,都可能与其余的顶点发生连接。如果不对访问的顶点做一些处理,出发重复访问的几率是很高的。因此,一个基本思想是设置一个标记数组,主要用于标记已经被访问过的顶点。图的遍历算法主要有两种:深度优先遍历和广度优先遍历。本篇文章主要介绍的是深度优先遍历算法。

深度优先遍历的具体过程

深度优先遍历,简称DFS。具体思想是不放过任何一个死角。在图的遍历中就是从图的某个顶点v出发,访问此顶点,然后从v的未被访问过的邻接点出发深度优先遍历图,直至图中的所有和v有路径相通的顶点都被访问到(对于连通图来讲)。

为了更好说明深度优先遍历的过程,以下面的图为例:

上图的邻接表定义如下:

注意:顶点0的第一个元素是2而不是5,其顶点类似。

  1. 起点是顶点0,后面的遍历过程从顶点0开始,把顶点0标记为已访问
  2. 因为顶点2是顶点0的邻接表的第一个元素,所以下一次递归从顶点2开始,同时把顶点2标记为已访问
  3. 顶点2的递归遍历开始,由于顶点2的邻接表的第一个元素是0,但是0已经被访问过了,所以访问顶点1,1没有被访问,于是将1标记为已访问,递归继续从顶点1开始
  4. 查找上表中顶点1的第一个元素,是顶点0,由于已经被访问过,所以访问顶点2,2也被访问过了,于是从顶点1的递归遍历结束,返回到顶点2继续递归。
  5. 查找顶点2的下一个元素,顶点3,没有被访问,于是将顶点3标记为已访问,递归于是从顶点3开始
  6. 查找顶点3邻接表的第一个元素,是顶点5,没有被访问,于是将顶点5标记为已访问,递归从顶点5开始
  7. 顶点5从其邻接表查找第一个元素,是顶点3,已被访问过,继续查找顶点0,也被访问,于是递归从5结束,返回到顶点3继续递归
  8. 查找顶点3邻接表的下一个元素,是顶点4,没有被访问过,于是将顶点4标记为已访问,递归从顶点4继续开始
  9. 顶点4查找其邻接表的第一个元素,发现顶点3已被访问过,继续查找其下一个元素,发现顶点2也被访问过,于是递归从顶点4结束,返回到顶点3继续递归
  10. 顶点查找下一个元素是顶点2了,也是顶点3邻接表的最后一个元素,发现顶点2已经被访问过了,所以递归从顶点3结束,返回到顶点2继续递归
  11. 顶点查找其邻接表的下一个元素,是顶点4,也是其邻接表最后一个元素,发现顶点已被访问过,所以递归从顶点2结束,返回到顶点0继续递归
  12. 顶点0继续查找其邻接表的下一个元素,发现顶点1余顶点5都被访问过了,所以递归结束。总的遍历结束。

从以上过程来看,上图的顶点访问次序依次是:0,2,1,3,5,4。

深度优先遍历算法的实现

首先需要定义一个存储图的数据结构,在Java中可以使用邻接表来实现图存储。具体而言就是,图的顶点用一维数组存储,每个顶点的邻接顶点用一个单链表进行存储。

图的数据结构:邻接表的实现

package com.rhwayfun.algorithm.graph;public class MyGraph {//顶点数目private int V;//边的数目private int E;//邻接表private Bag<Integer>[] adj;public MyGraph(int V){this.V = V;this.E = 0;//创建邻接表adj = (Bag<Integer>[])new Bag[V];//将所有链表初始化for(int v = 0; v < V; v++){adj[v] = new Bag<Integer>();}}public int V(){return V;}public int E(){return E;}public void addEdge(int v,int w){//将w添加到v的链表中adj[v].add(w);//将v添加到w的链表中adj[w].add(v);E++;}//获取顶点v的邻接表顶点列表public Iterable<Integer> adj(int v){return adj[v];}
}

深度优先遍历算法的实现代码:

package com.rhwayfun.algorithm.graph;/*** 深度优先搜索* <p>Title:DepthFirstSearch</p>* <p>Description:</p>* @author rhwayfun* @date Dec 22, 2015 8:04:23 PM* @version 1.0*/
public class DepthFirstSearch {//创建一个标记数组private boolean[] marked;//访问计数器private int count;/*** 构造一幅图并进行深度优先遍历* <p>Description: </p>* @param G 读入的图* @param s 开始遍历的顶点*/public DepthFirstSearch(MyGraph G,int s) {marked = new boolean[G.V()];dfs(G,s);}private void dfs(MyGraph G, int s) {marked[s] = true;count++;System.out.print(s + " ");for(int w : G.adj(s)){//如果没有被访问过就继续遍历if(!marked[w]) dfs(G, w);}}public boolean[] getMarked() {return marked;}public int getCount() {return count;}}

深度优先遍历算法的非递归实现方式

使用非递归的方式与递归的思想是一致的,不同的在于需要使用一个栈保存遍历的顶点。下面是具体的实现代码:

package com.rhwayfun.algorithm.graph;import java.util.Iterator;
import java.util.Stack;/*** 使用非递归方式对图进行深度优先遍历* <p>Title:NonrecursiveDFS</p>* <p>Description:</p>* @author rhwayfun* @date Dec 22, 2015 10:43:35 PM* @version 1.0*/
public class NonrecursiveDFS {//创建一个标记数组标记访问过的元素private boolean[] marked;@SuppressWarnings("unchecked")public NonrecursiveDFS(MyGraph G, int s){marked = new boolean[G.V()];//创建一个迭代器迭代每个顶点的邻接表Iterator<Integer>[] adj = (Iterator<Integer>[])new Iterator[G.V()];//获得每个顶点的邻接表for(int v = 0; v < G.V(); v++){adj[v] = G.adj(v).iterator();}//创建一个栈用户存放遍历的顶点Stack<Integer> stack = new Stack<Integer>();marked[s] = true;System.out.print(s + " ");stack.add(s);while(!stack.isEmpty()){int v = stack.peek();//如果有邻接表的话,就继续遍历if(adj[v].hasNext()){int w = adj[v].next();//判断是否已被访问过if(!marked[w]){//没访问过就将器标记为已访问过,下次不会再访问了marked[w] = true;System.out.print(w + " ");stack.push(w);}}else{//如果没有邻接表的话就将该顶点弹出栈顶stack.pop();}}}public boolean marked(int v) {return marked[v];}}

来自:https://blog.csdn.net/u011116672/article/details/50383221

图的深度优先遍历算法相关推荐

  1. 417. 太平洋大西洋水流问题(medium) -力扣(leetCode)逆流而上,JS图的深度优先遍历算法

    ⚡️417. 太平洋大西洋水流问题⚡️ 给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度."太平洋"处于大陆的左边界和上边界,而"大西洋"处 ...

  2. 图的遍历(搜索)算法 之 深度优先遍历算法

    图的遍历的定义: 从图中的某个顶点出发访问遍图中的所有顶点,并且每个顶点仅仅被访问一次. 图的遍历算法我们常见的而且用的最多的就有两种:其一是图的深度优先遍历算法:其二是图的广度优先遍历算法.这里我们 ...

  3. java随机生成迷宫(图的深度优先遍历)

    最近经常在机房看同学在玩一个走迷宫的游戏,比较有趣,自己也用java写一个实现随机生成迷宫的算法,其实就是一个图的深度优先遍历算法.基本思想就是,迷宫中的每个点都有四面墙,然后呢, 从任意一点开始访问 ...

  4. 图的深度优先遍历DFS(JAVA)

    图的深度优先遍历算法 在此介绍图的基本算法之一的深度优先遍历(DFS)算法 广度优先搜索(BFS). 什么是DFS 图是由节点(Node)和路径(Route)组成的一种数据结构,用于反应各节点间的关系 ...

  5. 分别用邻接矩阵和邻接表实现图的深度优先遍历和广度优先遍历_数据结构与算法学习笔记:图...

    图: 图结构区别于线性结构和树型结构,区别可见下图 逻辑上的图(graph)结构由顶点(vertex)和边(edge)组成. 一个图结构G包含顶点集合V和边集合E,任何两个顶点之间可以有一个边表示两者 ...

  6. educoder数据结构与算法 图 第2关:实现图的深度优先遍历

    任务描述 本关任务:实现 graph.cpp 里的函数int Graph_DepthFirst(Graph*g, int start, Edge* tree). 注意遵守约定:编号大的先进栈. 相关知 ...

  7. 算法学习:图的深度优先遍历(DFS)

    图的深度优先遍历 采用邻接矩阵表示图的方法,递归实现. 栈的使用: 头文件:<stack> s.empty():栈空则返回true,否则返回false s.top():返回栈顶元素,不删除 ...

  8. 广度优先搜索生成树怎么画_图的深度优先遍历与广度优先遍历以及最小生成树...

    图的深度优先遍历 题目:写出附从每个顶点出发的一次深度优先搜索遍历序列.在纸上画出遍历过程和序列,提交截图. 错误回答 从A点开始遍历:0124-01324-0134-0324-034 从B点开始遍历 ...

  9. C++实现图的深度优先遍历和广度优先遍历

    图的深度和广度优先遍历 图的深度优先遍历 1.算法思想 2.邻接矩阵构造图 3.邻接表构造图 图的广度优先遍历 1.算法思想 2.邻接矩阵构造图 图的深度优先遍历 1.算法思想 (1)从图中的某个初始 ...

  10. 图的深度优先遍历+图解

    图解 代码实现 package com.atguigu.graph;import java.util.ArrayList; import java.util.Arrays;/*** @创建人 wdl* ...

最新文章

  1. 20151020sql2
  2. 系统访问慢的几个原因
  3. 易创课堂深圳干货,趁热下载
  4. Flume监听文件夹中的文件变化,并把文件下沉到hdfs
  5. 有三角形的即时通讯源码?
  6. 动态规划 —— 背包问题 P09 —— 背包问题的变化
  7. mysql的介绍和安装
  8. OPPO K9s官宣:5000mAh超大电量 充电功率阉割明显
  9. escape character.
  10. Mysql学习笔记(一)数据类型
  11. linux基本管理命令,linux常用命令与基本管理
  12. delphi中WMI的使用(一)
  13. 2022年APP系统软件开发费用一览表介绍
  14. 数据结构试卷及答案(四)
  15. 设置小程序video标签宽高比例为9/16
  16. python全栈工程师待遇如何_python全栈工程师工作待遇
  17. C#将word文档转为PDF
  18. 阿里巴巴国际站业务如何写出高效便捷的客户开发跟进邮件?
  19. 红色警戒常用的快捷键
  20. 从前有座山,山上有两台计算机

热门文章

  1. 通过蓝牙连接进行ActiveSync同步
  2. k3服务器重装系统,金蝶K3安装教程07:K3 WEB系统配置工具
  3. Fujitsu DPK8310Tax 打印机驱动
  4. python实现网络爬虫下载天涯论坛帖子
  5. cpu测试稳定性软件,测试CPU稳定性工具Prime95
  6. 关于Vue中v-if 和 v-for一起使用
  7. inception-v1 自复现 有问题尽管问
  8. 多关卡连连看php源码_哆啦A梦连连看游戏源码完整版
  9. 软件架构入门及分类——微服务架构
  10. 硬盘扩容linux重新检查,Linux 无损扩容磁盘