版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

一、深度优先搜索介绍

图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。

它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

显然,深度优先搜索是一个递归的过程。

二、深度优先搜索图解

1 无向图的深度优先搜索

下面以"无向图"为例,来对深度优先搜索进行演示。

对上面的图G1进行深度优先遍历,从顶点A开始。

  1. 第1步:访问A。
  2. 第2步:访问(A的邻接点)C。 在第1步访问A之后,接下来应该访问的是A的邻接点,即"C,D,F"中的一个。但在本文的实现中,顶点ABCDEFG是按照顺序存储,C在"D和F"的前面,因此,先访问C。
  3. 第3步:访问(C的邻接点)B。 在第2步访问C之后,接下来应该访问C的邻接点,即"B和D"中一个(A已经被访问过,就不算在内)。而由于B在D之前,先访问B。
  4. 第4步:访问(C的邻接点)D。 在第3步访问了C的邻接点B之后,B没有未被访问的邻接点;因此,返回到访问C的另一个邻接点D。
  5. 第5步:访问(A的邻接点)F。 前面已经访问了A,并且访问完了"A的邻接点B的所有邻接点(包括递归的邻接点在内)";因此,此时返回到访问A的另一个邻接点F。
  6. 第6步:访问(F的邻接点)G。
  7. 第7步:访问(G的邻接点)E。

因此访问顺序是:A -> C -> B -> D -> F -> G -> E

2.有向图的深度优先搜索

下面以"有向图"为例,来对深度优先搜索进行演示。

对上面的图G2进行深度优先遍历,从顶点A开始。

  1. 第1步:访问A。
  2. 第2步:访问B。 在访问了A之后,接下来应该访问的是A的出边的另一个顶点,即顶点B。
  3. 第3步:访问C。在访问了B之后,接下来应该访问的是B的出边的另一个顶点,即顶点C,E,F。在本文实现的图中,顶点ABCDEFG按照顺序存储,因此先访问C。
  4. 第4步:访问E。接下来访问C的出边的另一个顶点,即顶点E。
  5. 第5步:访问D。接下来访问E的出边的另一个顶点,即顶点B,D。顶点B已经被访问过,因此访问顶点D。
  6. 第6步:访问F。 接下应该回溯"访问A的出边的另一个顶点F"。
  7. 第7步:访问G。

因此访问顺序是:A -> B -> C -> E -> D -> F -> G

三、代码实现

private boolean[] isVisited = new boolean[vertextSize];

/**
* 获取指定顶点的第一个邻接点
*
* @param index
* 指定邻接点
* @return
*/
private int getFirstNeighbor(int index) {
for (int i = 0; i < vertexSize; i++) {
if (matrix[index][i] < MAX_WEIGHT && matrix[index][i] > 0) {
return i;
}
}
return -1;
} /**
* 获取指定顶点的下一个邻接点
*
* @param v
* 指定的顶点
* @param index
* 从哪个邻接点开始
* @return
*/
private int getNextNeighbor(int v, int index) {
for (int i = index+1; i < vertexSize; i++) {
if (matrix[v][i] < MAX_WEIGHT && matrix[v][i] > 0) {
return i;
}
}
return -1;
} /**
* 图的深度优先遍历算法
*/
private void depthFirstSearch(int i) {
isVisited[i] = true;
int w = getFirstNeighbor(i);
while (w != -1) {
if (!isVisited[w]) {
// 需要遍历该顶点
System.out.println("访问到了:" + w + "顶点");
depthFirstSearch(w); // 进行深度遍历
}
w = getNextNeighbor(i, w); // 第一个相对于w的邻接点
}
}
  • 0进去,表示v0
  • 设置v0已访问过,获取v0第一个邻接点w != -1说明有这个邻接点,然后对这个临界点进行判断。
    • 已访问,那就找下一个临界点
    • 未访问,进行访问,然后对该邻接点进行深度优先遍历

四、总结

  • 遍历规则:不断的沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。
  • 它从图中某个顶点v出发,访问此顶点,然后从顶点的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。
  • 简单说,就是顶点将第一个邻接点当作左孩子,其它邻接点都当做右孩子。最后排成一棵树。
  • 深度优先遍历是指先遍历到最深层次然后再探索邻接点,接着又遍历最深层次。二叉树的先序遍历就是一种深度优先遍历。

我的微信公众号:架构真经(id:gentoo666),分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。每日更新哦!

参考资料:

  1. https://blog.csdn.net/Strive_Y/article/details/81810012
  2. https://www.jianshu.com/p/23b55db1adc0

程序员的算法课(17)-常用的图算法:深度优先(DFS)的更多相关文章

  1. 程序员的算法课(18)-常用的图算法:广度优先(BFS)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  2. 程序员的算法课(19)-常用的图算法:最短路径(Shortest Path)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  3. 程序员的算法课(20)-常用的图算法:最小生成树(MST)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  4. 程序员的算法课(3)-递归(recursion)算法

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  5. 程序员的算法课(16)-B+树在数据库索引中的作用

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  6. 程序员的算法课(14)-Hash算法-对海量url判重

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  7. 程序员的算法课(11)-KMP算法

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  8. 程序员的算法课(6)-最长公共子序列(LCS)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  9. 给c++程序员的一份礼物——常用工具集

    给c++程序员的一份礼物——常用工具集 [声明]如需复制.传播,请附上本声明,谢谢.原文出处:http://morningspace.51.net/,moyingzz@etang.com 所谓&quo ...

随机推荐

  1. 2018.8.15 python 中的sorted()、filter()、map()函数

    主要内容: 1.lambda匿名函数 2.sorted() 3.filter() 4.map() 5.递归函数 一. lambda匿名函数 为了解决一些简单的需求而设计的一句话函数 # 计算n的n次方 ...

  2. 重新认识MySQL中的COUNT语句

    在数据库的增删改查操作中,使用最频繁的就是查询操作. 而在所有查询操作中,统计数量操作更是经常被用到. 关于数据库中行数统计,无论是MySQL还是Oracle亦或者是SqlServer,都有一个函数可 ...

  3. Head First设计模式——简单工厂、工厂、抽象工厂

    前言:按照惯例我以Head First设计模式的工厂模式例子开始编码学习.并由简单工厂,工厂模式,抽象工厂模式依次演变,归纳他们的相同与不同. 话说Head First认为简单工厂并不是设计模式,而是 ...

  4. H5与CSS3常用设置

    1.设置div铺满全屏 对于一个div1,要使其属性height:100%生效,需要使其所有父元素,有确定的属性height.要铺满全屏,就是从html开始,所有的height为100%. 2.垂直居 ...

  5. MATLAB实例:聚类初始化方法与数据归一化方法

    MATLAB实例:聚类初始化方法与数据归一化方法 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 1. 聚类初始化方法:init_methods.m f ...

  6. Ambari 集群时间同步配置教程

    本文原始地址:https://sitoi.cn/posts/27560.html 步骤 在时间同步主节点创建 ntp.conf 文件 在时间同步从节点上创建 ntp.conf 文件 修改所有节点时区 ...

  7. 卡特兰数&&prufer序列&&BSGS水题集

    首先说一下BSGS的一个坑点: 解方程A^x≡B(mod p) 需要特判一个东西=>A%p==B%p==0? 如果相等的话puts("1")反之则无解. 因为如果A%p=0, ...

  8. JVM初体验

    一.设计堆内存溢出异常:OutOfMemoryError: public class Main { public static void main(String[] args) { List<D ...

  9. What's your name?

    Hello. My name is james. What's your name? Hi, I'm Jessica. Nice to meet you. Nice to meet you, too. ...

  10. Python类属性与实例属性理解

    按理讲,类属性改变,类的实例对象这个属性也应该被改变,但是在python中实际却不是这样 class test(): name = 111 a = test() b = test() a.name = ...