JAVA数据结构——利用图的广度优先遍历搜索算法确定无向连通图的连通分量

2023-11-19

分析:

如果这个无向图是非连通图的时候,从图的一个顶点没法访问这个图的所有顶点,只能访问包含该顶点的连通分量中的所有顶点。所以从无向图的每个连通分量中的一个顶点开始遍历图,则可求得无向图的所有连同分量。

如图则是非连通的无向图,我们只需要从第一个和第二个连通分量进行遍历即可,先了解一下基础设想。

从1-2-...n,我们可以把这个思路无限制扩大下去,实现若干个非连通图如何实现。

我们采用广度优先遍历搜索算法来实现这个功能。

广度优先遍历搜索(BFS):

广度优先遍历,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

已知图G=(V,E)和一个源顶点s,宽度优先搜索以一种系统的方式探寻G的边,从而“发现”s所能到达的所有顶点,并计算s到所有这些顶点的距离(最少边数),该算法同时能生成一棵根为s且包括所有可达顶点的宽度优先树。对从s可达的任意顶点v,宽度优先树中从s到v的路径对应于图G中从s到v的最短路径,即包含最小边数的路径。该算法对有向图和无向图同样适用。
之所以称之为宽度优先算法,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点。
       为了保持搜索的轨迹,宽度优先搜索为每个顶点着色:白色、灰色或黑色。算法开始前所有顶点都是白色,随着搜索的进行,各顶点会逐渐变成灰色,然后成为黑色。在搜索中第一次碰到一顶点时,我们说该顶点被发现,此时该顶点变为非白色顶点。因此,灰色和黑色顶点都已被发现,但是,宽度优先搜索算法对它们加以区分以保证搜索以宽度优先的方式执行。若(u,v)∈E且顶点u为黑色,那么顶点v要么是灰色,要么是黑色,就是说,所有和黑色顶点邻接的顶点都已被发现。灰色顶点可以与一些白色顶点相邻接,它们代表着已找到和未找到顶点之间的边界。
       在宽度优先搜索过程中建立了一棵宽度优先树,起始时只包含根节点,即源顶点s.在扫描已发现顶点u的邻接表的过程中每发现一个白色顶点v,该顶点v及边(u,v)就被添加到树中。在宽度优先树中,我们称结点u 是结点v的先辈或父母结点。因为一个结点至多只能被发现一次,因此它最多只能有--个父母结点。相对根结点来说祖先和后裔关系的定义和通常一样:如果u处于树中从根s到结点v的路径中,那么u称为v的祖先,v是u的后裔。

代码实现利用广度优先遍历搜索确定无向图的连通分量: 

1. 图类型:

package com.usts.edu.graphic;

// 图的种类 有向图、有向网、无向图、无向网
public enum GraphKind {
	UDG, // 无向图(UnDirected Graph)
	DG, // 有向图(Directed Graph)
	UDN, // 无向网(UnDirected Network)
	DN; // 有向网(Directed Network)
}

2. 图的接口 

package com.usts.edu.graphic;

//图的接口
public interface IGraph {
	void createGraph();//创建一个图

	int getVexNum(); // 返回顶点数

	int getArcNum();// 返回边数

	Object getVex(int v) throws Exception;// 返回v表示结点的值, 0 <= v < vexNum

	int locateVex(Object vex);// 给定顶点的值vex,返回其在图中的位置,如果图中不包含此顶点,则返回-1

	int firstAdjVex(int v) throws Exception; // 返回v的第一个邻接点,若v没有邻接点,则返回-1,其中0≤v<vexNum

	int nextAdjVex(int v, int w) throws Exception;// 返回v相对于w的下一个邻接点,若w是v的最后一个邻接点,则返回-1,其中0≤v, w<vexNum

}

 3. 创建图:

package com.usts.edu.graphic;

import java.util.Scanner;


public class MGraph implements IGraph {
	public final static int INFINITY = Integer.MAX_VALUE;

	private GraphKind kind;

	private int vexNum, arcNum;

	private Object[] vexs;

	private int[][] arcs;

	public MGraph() {
		this(null, 0, 0, null, null);
	}

	public MGraph(GraphKind kind, int vexNum, int arcNum, Object[] vexs,
			int[][] arcs) {
		this.kind = kind;
		this.vexNum = vexNum;
		this.arcNum = arcNum;
		this.vexs = vexs;
		this.arcs = arcs;
	}

	public void createGraph() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入图的类型");
		GraphKind kind = GraphKind.valueOf(sc.next());
		switch (kind) {
		case UDG:
			createUDG();
			return;
		case DG:
			createDG();
			return;
		case UDN:
			createUDN();
			return;
		case DN:
			createDN();
			return;
		}
	}

	private void createUDG() {
	};

	private void createDG() {
	};

	private void createUDN() {
		Scanner sc = new Scanner(System.in);
		vexNum = sc.nextInt();
		arcNum = sc.nextInt();
		vexs = new Object[vexNum];
		for (int v = 0; v < vexNum; v++)
			vexs[v] = sc.next();

		arcs = new int[vexNum][vexNum];
		for (int v = 0; v < vexNum; v++)
			for (int u = 0; u < vexNum; u++)
				arcs[v][u] = INFINITY;

		for (int k = 0; k < arcNum; k++) {
			int v = locateVex(sc.next());
			int u = locateVex(sc.next());
			arcs[v][u] = arcs[u][v] = sc.nextInt();
		}
	}

	private void createDN() {
		Scanner sc = new Scanner(System.in);
		vexNum = sc.nextInt();
		arcNum = sc.nextInt();
		vexs = new Object[vexNum];
		for (int v = 0; v < vexNum; v++)
			vexs[v] = sc.next();

		arcs = new int[vexNum][vexNum];
		for (int v = 0; v < vexNum; v++)
			for (int u = 0; u < vexNum; u++)
				arcs[v][u] = INFINITY;

		for (int k = 0; k < arcNum; k++) {
			int v = locateVex(sc.next());
			int u = locateVex(sc.next());
			arcs[v][u] = sc.nextInt();
		}

	}

	public int getVexNum() {
		return vexNum;
	}

	public int getArcNum() {
		return arcNum;
	}

	public int locateVex(Object vex) {
		for (int v = 0; v < vexNum; v++)
			if (vexs[v].equals(vex))
				return v;
		return -1;
	}

	public Object getVex(int v) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "个顶点不存在!");
		return vexs[v];
	}

	public int firstAdjVex(int v) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "个顶点不存在!");

		for (int j = 0; j < vexNum; j++)
			if (arcs[v][j] != 0 && arcs[v][j] < INFINITY)
				return j;

		return -1;
	}

	public int nextAdjVex(int v, int w) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "个顶点不存在!");

		for (int j = w + 1; j < vexNum; j++)
			if (arcs[v][j] != 0 && arcs[v][j] < INFINITY)
				return j;

		return -1;
	}

	public GraphKind getKind() {
		return kind;
	}

	public int[][] getArcs() {
		return arcs;
	}

	public Object[] getVexs() {
		return vexs;
	}

	public void setArcNum(int arcNum) {
		this.arcNum = arcNum;
	}

	public void setArcs(int[][] arcs) {
		this.arcs = arcs;
	}

	public void setKind(GraphKind kind) {
		this.kind = kind;
	}

	public void setVexNum(int vexNum) {
		this.vexNum = vexNum;
	}

	public void setVexs(Object[] vexs) {
		this.vexs = vexs;
	}

}

4. 实现搜索:

 

package com.usts.edu.graphic;

import com.usts.edu.Queue.LinkQueue;

/**
 * Created by Guanzhong Hu
 * Date :2020/3/30
 * Description :
 * Version :1.0
 */
public class GDSeach {
        public final static int INFINITY = Integer.MAX_VALUE;

        public static void CC_BFS(IGraph G) throws Exception {
            boolean[] visited = new boolean[G.getVexNum()];
            for (int v = 0; v < G.getVexNum(); v++)

                visited[v] = false;
            LinkQueue Q = new LinkQueue();
            LinkQueue P = new LinkQueue();
            int i = 0;
            for (int v = 0; v < G.getVexNum(); v++) {
                P.clear();
                if (!visited[v]) {
                    visited[v] = true;
                    P.offer(G.getVex(v));
                    Q.offer(v);
                    while (!Q.isEmpty()) {
                        int u = (Integer) Q.poll();
                        for (int w = G.firstAdjVex(u); w >= 0; w = G.nextAdjVex(u,
                                w)) {
                            if (!visited[w]) {
                                visited[w] = true;
                                P.offer(G.getVex(w));
                                Q.offer(w);
                            }
                        }
                    }
                    System.out.println("图的第" + ++i + "个连通分量为:");
                    while (!P.isEmpty())
                        System.out.print(P.poll().toString() + " ");
                    System.out.println();
                }
            }
        }

        public static void main(String[] args) throws Exception {
            Object vexs[] = { "A", "B", "C", "D", "E", "F", "G" };
            int[][] arcs = { { 0, 1, INFINITY, 1, INFINITY, INFINITY, INFINITY },
                    { 1, 0, 1, INFINITY, INFINITY, INFINITY, INFINITY },
                    { INFINITY, 1, 0, 1, INFINITY, INFINITY, INFINITY },
                    { 1, INFINITY, 1, 0, INFINITY, INFINITY, INFINITY },
                    { INFINITY, INFINITY, INFINITY, INFINITY, 0, 1, INFINITY },
                    { INFINITY, INFINITY, INFINITY, INFINITY, 1, 0, 1 },
                    { INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, 1, 0 }, };
            MGraph G = new MGraph(GraphKind.UDG, 7, 6, vexs, arcs);
            CC_BFS(G);
        }
}

无向图的连通分量搜索是一种广度优先遍历的应用,当然还有如Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。

源码地址:https://gitee.com/jockhome/data_structure

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA数据结构——利用图的广度优先遍历搜索算法确定无向连通图的连通分量 的相关文章

随机推荐

  • 计算机网络——数字数据的数字编码

    计算机网络 数字数据的数字编码 数字数据的数字编码就是如何把数字数据用物理信号的波形表示 即用高低电平表示二进制 1 不归零码 正电平代表1 负电平代表0 2 归零码 正脉冲代表1 负脉冲代表0 3 曼彻斯特编码 位周期中心的上跳代表0 周
  • 吴恩达与OpenAI官方合作的ChatGPT提示工程课程笔记

    吴恩达与OpenAI官方合作的ChatGPT提示工程课程笔记 下述代码均在煮皮特上运行喔 LLMs large language models Base LLM 基于文本训练数据来预测做 文字接龙 Instruction Tuned LLM
  • git小技巧:git blame && git show 查看某一行代码的修改历史

    先查看某行代码由谁写的 在哪个commit中提交的 git blame file name 其显示格式为 commit ID 代码提交作者 提交时间 代码位于文件中的行数 实际代码 类似于下面这样 f604879e yingyinl 201
  • 某某星图sign参数解密分析

    大家好 我是TheWeiJun 欢迎来到我的公众号 今天给大家带来星图sign参数的解密分析 希望大家能够喜欢 如果你觉得我的文章内容有价值 记得点赞 关注 特别声明 本公众号文章只作为学术研究 不用于其他用途 逆向与爬虫的故事 公众号 专
  • 主线程退出后,子线程会不会退出

    额 好吧 这是个标题党 其实所有的线程都是平级的 根本不存在主线程和子线程 下文所述为了方便 将在main函数中的线程看做主线程 其它线程看成子线程 特此说明 先考虑以下代码 include
  • 基于深度学习的正常衰老和痴呆症中的脑龄预测

    大脑衰老过程中会出现一系列功能和结构的改变 阿尔茨海默病 AD 作为一种典型的神经退行性疾病 与大脑加速衰老有关联 在本研究中 我们利用大量的氟脱氧葡萄糖正电子发射断层扫描 FDG PET 和结构磁共振成像 MRI 数据 构建了一个基于深度
  • 期货开户顺大市而逆小市

    期货的行情 有人愿意以更高的价来买入 就会涨 有人买意以更低的价格卖出 就会跌 现货市场上 一个馒头5角钱的时候 在期货市场上 如果有很多人争着买 这个馒头可能会涨到5块 或者50块 也是可能的 在这个馒头5块钱一个的时候 你感觉这个馒头太
  • Servlet+JDBC实战开发书店项目讲解第五篇:购物车实现

    Servlet JDBC实战开发书店项目讲解第五篇 购物车实现 引言 在之前的几篇博客中 我们讲解了如何使用Servlet和JDBC开发一个简单的书店管理系统 在本文中 我们将深入探讨购物车的实现 这是一个关键功能 允许用户将所需图书添加到
  • Java的多态特性

    学习笔记 多态 简单说 就是一个对象对应着不同类型 多态在代码中的体现 父类或者接口的引用指向其子类的对象 多态的好处 提高可维护性 由多态前提所保证 提高了代码的扩展性 多态的弊端 无法直接访问子类特有的成员 也就是说前期定义的内容不能使
  • [C++基础]-stack和queue

    前言 作者 小蜗牛向前冲 名言 我可以接受失败 但我不能接受放弃 如果觉的博主的文章还不错的话 还请点赞 收藏 关注 支持博主 如果发现有问题的地方欢迎 大家在评论区指正 目录 一 stack的基本知识 1 什么是栈 2 栈的基本使用 3
  • Python 使用execjs调用网页js 进行数据加密

    最近做一个数据采集项目的时候需要自动采集网站的招投标数据 随便打开一个网站 打开开发者模式 输入关键词 点击搜索 获得以下内容 可以看到请求链接和请求类型 请求类型Content Type 是application x www form u
  • maven 项目导入junit问题

    maven项目无法导入 import org junit Test import org junit runner RunWith 问题 1 检查 Maven Dependencies中Junit的jar中是否有此类 如果没有 说明pom
  • 判断一个IP地址是不是单播地址

    1 组播地址 2 单播地址 1 2
  • C++_生成随机字符串

    include
  • Vite配置跨域代理

    Vite 配置跨域代理 修改vite config js文件 import defineConfig from vite import react from vitejs plugin react https vitejs dev conf
  • Xilinx AXI-memory接口 转 AXI-stream 接口(含源码)

    AXI memory接口 转 AXI stream 接口 AXI memory接口介绍 具体详情可以查看源码 AXI memory接口介绍 从图中我们可以看出memory接口有5个通道 分别是读地址通道 写地址通道 写响应通道 读数据通道
  • 华为OD两轮技术面试

    华为OD面试 1性格测试 选积极向上的选项 注意 性格测试也会挂人 我一个朋友性格测试就没过 2机试 一道变成题目 1h 用例60 通过即可 任给一个数组 元素有20M 1T 300G之类的 其中1T 1000G 1G 1000M 按从小到
  • 数据库事务锁详解

    前言 上篇说到数据库事务中的特性ACID和4个隔离级别 今儿就来看一下事务中的锁 MySQL中的锁 锁是MySQL在服务器层和存储引擎层的并发控制 锁可以保证数据并发访问的一致性 有效性 锁冲突也是影响数据库并发访问性能的一个重要因素 My
  • 并发编程4 - 线程状态、死锁及ReentrantLock

    文章目录 一 再述线程状态转换 二 多把锁与线程活跃性问题 1 多把锁 2 活跃性 三 ReEntrantLock 1 基本用法 2 可重入 3 可打断 4 锁超时 5 公平锁 6 条件变量 一 再述线程状态转换 情况1 New RUNNA
  • JAVA数据结构——利用图的广度优先遍历搜索算法确定无向连通图的连通分量

    分析 如果这个无向图是非连通图的时候 从图的一个顶点没法访问这个图的所有顶点 只能访问包含该顶点的连通分量中的所有顶点 所以从无向图的每个连通分量中的一个顶点开始遍历图 则可求得无向图的所有连同分量 如图则是非连通的无向图 我们只需要从第一