【算法基础实验】图论-基于DFS的连通性检测

2024-04-27 07:04

本文主要是介绍【算法基础实验】图论-基于DFS的连通性检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于DFS的连通性检测

理论基础

在图论中,连通分量是无向图的一个重要概念,特别是在处理图的结构和解析图的组成时。连通分组件表示图中的一个子图,在这个子图中任意两个顶点都是连通的,即存在一条路径可以从一个顶点到达另一个顶点,并且这个子图是最大的,即不能通过添加更多的顶点来增加连通性。对于有向图,这通常被称为强连通分量。

基于DFS的连通分量算法

书中4.1.6节提到的基于深度优先搜索(DFS)的连通分量算法用于识别和处理无向图中的连通分量。这个算法的基本思想是使用DFS遍历图中的每个顶点,同时记录哪些顶点是连通的。

算法步骤

  1. 初始化:为每个顶点准备一个标记数组 marked[] 来记录每个顶点是否被访问过,另外用一个数组 id[] 来记录每个顶点所属的连通分量的标识符。还需要一个计数器 count 来统计连通分量的数量。
  2. DFS遍历:从任意未被访问的顶点开始,执行DFS遍历。在遍历过程中,标记所有可达的顶点为已访问,同时将这些顶点的 id[] 设置为当前的连通分量标识符。
  3. 连通分量标识:每次在DFS遍历开始前增加连通分量计数器 count,并将遍历过程中访问的所有顶点的连通分量标识设置为这个计数器的值。
  4. 重复执行:重复上述过程,直到图中的所有顶点都被访问过。

应用

  • 图的结构分析:识别图中的独立部分或者紧密相关的群组。
  • 网络设计:确定网络中的独立组件,以优化设计和提高稳定性。
  • 社交网络:识别社交网络中的社区或者群组。

通过这种基于DFS的连通分量算法,可以有效地解析和处理图的结构,对于复杂网络的分析尤其有用。

数据结构

private boolean[] marked
private int[] id
private int count
myBag
myGraph

实验数据和算法流程

这里使用tinyG.txt来构成实验用的无向图

注意算法流程中count,marked[],id[]的变化

请添加图片描述

代码实现

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;public class myCC {private boolean[] marked;private int[] id;private int count;public myCC(myGraph G){marked = new boolean[G.V()];id = new int[G.V()];for(int s=0;s<G.V();s++){if(!marked[s]){dfs(G,s);//这里是精髓所在,每次dfs回到这里就说明互相连通的一组顶点已经完成遍历,//也就确定了一个连通分量count++;                }}}private void dfs(myGraph G, int v){marked[v] = true;id[v] = count;for(int w:G.adj(v)){if(!marked[w]){dfs(G,w);}}}public boolean connected(int v, int w){return id[v]==id[w];}public int id(int v){return id[v];}public int count(){return count;}public static void main(String[] args){myGraph G = new myGraph(new In(args[0]));myCC cc = new myCC(G);int M = cc.count();StdOut.println(M + " components");myBag<Integer>[] components = (myBag<Integer>[]) new myBag[M];for(int i=0;i<M;i++){components[i] = new myBag<Integer>();}for(int v=0;v<G.V();v++){components[cc.id(v)].add(v);}for(int i=0;i<M;i++){for(int v:components[i]) StdOut.print(v+" ");StdOut.println();}}
}

代码详解

这段代码实现了一个基于深度优先搜索(DFS)的连通分量(CC)类 myCC,用于确定无向图中所有的连通分量。下面是详细的代码解释:

类定义和变量


public class myCC {private boolean[] marked;  // 标记数组,用于标记每个顶点是否已经被访问过private int[] id;          // 每个顶点所属的连通分量标识private int count;         // 连通分量的数量
  • marked 数组用于记录图中的每个顶点是否已经被访问。
  • id 数组用于存储每个顶点所属的连通分量的ID。
  • count 用于计数图中连通分量的总数。

构造函数


public myCC(myGraph G){marked = new boolean[G.V()];id = new int[G.V()];for(int s = 0; s < G.V(); s++) {if (!marked[s]) {dfs(G, s);count++;  // 完成一个连通分量的搜索后,增加连通分量的计数}}
}

构造函数遍历图中的所有顶点,对于每个未标记的顶点,执行DFS来标记和记录所有能从该顶点访问到的顶点,这些顶点构成一个连通分量。每次DFS调用结束后,连通分量数 count 加一。

DFS 方法


private void dfs(myGraph G, int v){marked[v] = true;id[v] = count;for (int w : G.adj(v)) {if (!marked[w]) {dfs(G, w);}}
}

dfs 方法标记顶点 v 为已访问,并将其连通分量ID设置为当前的 count。然后递归地访问所有与顶点 v 直接相连的未标记顶点。

连通分量的辅助方法


public boolean connected(int v, int w) { return id[v] == id[w]; }
public int id(int v) { return id[v]; }
public int count() { return count; }

这些方法提供了:

  • connected(v, w) 检查两个顶点是否属于同一个连通分量。
  • id(v) 返回顶点 v 的连通分量ID。
  • count() 返回图中连通分量的总数。

主方法


public static void main(String[] args){myGraph G = new myGraph(new In(args[0]));myCC cc = new myCC(G);int M = cc.count();StdOut.println(M + " components");myBag<Integer>[] components = (myBag<Integer>[]) new myBag[M];for (int i = 0; i < M; i++) {components[i] = new myBag<Integer>();}for (int v = 0; v < G.V(); v++) {components[cc.id(v)].add(v);}for (int i = 0; i < M; i++) {for (int v : components[i]) StdOut.print(v + " ");StdOut.println();}
}

主方法使用 myCC 类来处理一个从文件读取的图,并输出所有的连通分量。这里,连通分量被存储在一个 myBag 数组中,每个 myBag 对象存储一个连通分量的所有顶点,然后输出每个连通分量的顶点。

这段代码是一个完整的图连通分量识别实现,使用DFS作为基本的遍历策略。

实验

代码编译

javac myCC.java

运行代码

将实验数据tinyG.txt导入代码后,myCC可以检测到3个连通分量,并逐行将连通分量中的元素打印出来

java myCC ..\data\tinyG.txt               
3 components
6 5 4 3 2 1 0
8 7
12 11 10 9

参考资料

算法(第4版)人民邮电出版社

这篇关于【算法基础实验】图论-基于DFS的连通性检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/939813

相关文章

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

Python脚本轻松实现检测麦克风功能

《Python脚本轻松实现检测麦克风功能》在进行音频处理或开发需要使用麦克风的应用程序时,确保麦克风功能正常是非常重要的,本文将介绍一个简单的Python脚本,能够帮助我们检测本地麦克风的功能,需要的... 目录轻松检测麦克风功能脚本介绍一、python环境准备二、代码解析三、使用方法四、知识扩展轻松检测麦

从基础到高阶详解Python多态实战应用指南

《从基础到高阶详解Python多态实战应用指南》这篇文章主要从基础到高阶为大家详细介绍Python中多态的相关应用与技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、多态的本质:python的“鸭子类型”哲学二、多态的三大实战场景场景1:数据处理管道——统一处理不同数据格式

MySQL数据类型与表操作全指南( 从基础到高级实践)

《MySQL数据类型与表操作全指南(从基础到高级实践)》本文详解MySQL数据类型分类(数值、日期/时间、字符串)及表操作(创建、修改、维护),涵盖优化技巧如数据类型选择、备份、分区,强调规范设计与... 目录mysql数据类型详解数值类型日期时间类型字符串类型表操作全解析创建表修改表结构添加列修改列删除列

Python 函数详解:从基础语法到高级使用技巧

《Python函数详解:从基础语法到高级使用技巧》本文基于实例代码,全面讲解Python函数的定义、参数传递、变量作用域及类型标注等知识点,帮助初学者快速掌握函数的使用技巧,感兴趣的朋友跟随小编一起... 目录一、函数的基本概念与作用二、函数的定义与调用1. 无参函数2. 带参函数3. 带返回值的函数4.

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon