• 深度优先遍历与连通分量


    深度优先遍历(Depth First Search)的主要思想是首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点。当没有未访问过的顶点时,则回到上一个顶点,继续试探别的顶点,直至所有的顶点都被访问过。

    下图示例的图从 0 开始遍历顺序如右图所示:

    无向图 G 的一个极大连通子图称为 G 的一个连通分量(或连通分支)。连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。连通分量与连通分量之间没有任何边相连。深度优先遍历可以用来求连通分量。

    下面以求连通分量为例,来实现图的深度优先遍历,称为 dfs。下面代码片段中,visited 数组记录 dfs 的过程中节点是否被访问,ccount 记录联通分量个数,id 数组代表每个节点所对应的联通分量标记,两个节点拥有相同的 id 值代表属于同一联通分量。

    1. ...
    2. // 构造函数, 求出无权图的联通分量
    3. public Components(Graph graph){
    4. // 算法初始化
    5. G = graph;
    6. visited = new boolean[G.V()];
    7. id = new int[G.V()];
    8. ccount = 0;
    9. for( int i = 0 ; i < G.V() ; i ++ ){
    10. visited[i] = false;
    11. id[i] = -1;
    12. }
    13. // 求图的联通分量
    14. for( int i = 0 ; i < G.V() ; i ++ )
    15. if( !visited[i] ){
    16. dfs(i);
    17. ccount ++;
    18. }
    19. }
    20. ...

    图的深度优先遍历是个递归过程,实现代码:

    1. ...
    2. // 图的深度优先遍历
    3. void dfs( int v ){
    4. visited[v] = true;
    5. id[v] = ccount;
    6. for( int i: G.adj(v) ){
    7. if( !visited[i] )
    8. dfs(i);
    9. }
    10. }
    11. ...

    Java 实例代码

    src/runoob/graph/Components.java 文件代码:

    1. package runoob.graph;
    2. import runoob.graph.read.Graph;
    3. /**
    4. * 深度优先遍历
    5. */
    6. public class Components {
    7. Graph G; // 图的引用
    8. private boolean[] visited; // 记录dfs的过程中节点是否被访问
    9. private int ccount; // 记录联通分量个数
    10. private int[] id; // 每个节点所对应的联通分量标记
    11. // 图的深度优先遍历
    12. void dfs( int v ){
    13. visited[v] = true;
    14. id[v] = ccount;
    15. for( int i: G.adj(v) ){
    16. if( !visited[i] )
    17. dfs(i);
    18. }
    19. }
    20. // 构造函数, 求出无权图的联通分量
    21. public Components(Graph graph){
    22. // 算法初始化
    23. G = graph;
    24. visited = new boolean[G.V()];
    25. id = new int[G.V()];
    26. ccount = 0;
    27. for( int i = 0 ; i < G.V() ; i ++ ){
    28. visited[i] = false;
    29. id[i] = -1;
    30. }
    31. // 求图的联通分量
    32. for( int i = 0 ; i < G.V() ; i ++ )
    33. if( !visited[i] ){
    34. dfs(i);
    35. ccount ++;
    36. }
    37. }
    38. // 返回图的联通分量个数
    39. int count(){
    40. return ccount;
    41. }
    42. // 查询点v和点w是否联通
    43. boolean isConnected( int v , int w ){
    44. assert v >= 0 && v < G.V();
    45. assert w >= 0 && w < G.V();
    46. return id[v] == id[w];
    47. }
    48. }
  • 相关阅读:
    在Spring中使用监听器以及事件监听机制
    设计模式:策略模式、工厂模式、模板模式混合使用
    Springboot 2.5.X框架解决跨域遇到的坑
    基于 Cloudflare Workers 和 cloudflare-docker-proxy 搭建镜像加速服务
    Spring Boot Admin -Actuator 图形化管理工具
    Python-爬虫 (BS4数据解析)
    数据变换:数据挖掘的准备工作之一
    农夫山泉2面面试经历
    Python的多重继承和MixIn
    Python学习路线
  • 原文地址:https://blog.csdn.net/weixin_45953332/article/details/134255674