当前位置: 首页 > news >正文

图----无向图

1.定义

图的定义:图是由一组顶点和一组能够将两个顶点相连的边组成

边:edge

顶点:vertex

 连通图:如果从任意一个顶点都存在一条路径到达另外一个任意顶点,我们称这幅图是连通图。

非连通图:由若干连通的部分组成,他们都是其极大连通子图。

自环:即一条连接一个顶点和其自身的边

平行边:连接同一顶点的两条边称为平行边

 图的密度:是指已经连接的顶点对占所有可能被连接的顶点对的比例。在稀疏图中,被连接的顶点对很少;而在稠密图中,只有少部分顶点对之间没有边连接。

二分图:是一种能够将所有结点分为两部分的图,其中图的每条边所连接的两个顶点都分别属于不同的部分。

2.图的不同表示方法

2.1邻接表数组表示

用一个以顶点为索引的列表数组,其中的每个元素都是和该顶点相邻的定点列表

 2.2邻接矩阵 表示

用一个V乘以V的布尔矩阵。当顶点V和顶点W之间有相连的边时,定义V行W列的元素值为true,否则为false。如果含有上百万个顶点,V的平方个布尔值所需要的空间会非常大。

3.相关API及代码

package com.sid.graph;public class Vertex {String value;//顶点的值Edge firstEdge;//第一条边int index;//在外层数组的下标public Vertex(String value, Edge firstEdge,int index) {super();this.value = value;this.firstEdge = firstEdge;this.index = index;}
}
package com.sid.graph;public class Edge {Vertex vertex;//该边对应的顶点int weight;//权重,无向图,有向图权重为0Edge next;//下一个边/*** 构建一条边 weight未0表示无向图或者有向图 不为0表示网* @param vertex* @param weight* @param next*/public Edge(Vertex vertex, int weight, Edge next) {super();this.vertex = vertex;this.weight = weight;this.next = next;}
}
package com.sid.graph;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Graph {/*** 顶点数*/private final int V;/*** 边数*/private int E;/*** 邻接表*/private List<Vertex> adj;public Graph(int V) {this.V = V;this.E = 0;adj = new ArrayList<Vertex>(V);  /** 创建邻接表 */}public int V() {return V;}public int E() {return E;}/*** 插入顶点*/public Vertex addVertex(String value) {int size = adj.size();Vertex vertex = new Vertex(value, null,size);adj.add(vertex);return vertex;}/*** 获取顶点*/public Vertex getVertexByValue(String value) {for (int i = 0; i < V; i++) {if (adj.get(i).value.equals(value)) {return adj.get(i);}}return null;}/*** 获取顶点*/public Vertex getVertexByIndex(int index) {return adj.get(index);}/*** 添加无向图的边* @param vertex1 第一个顶点* @param vertex2 第二个顶点*/public void addUndigraphEdge(Vertex vertex1,Vertex vertex2) {//因为是无向图,所以就直接加入addEdgeByVertex(vertex1,vertex2,0);addEdgeByVertex(vertex2,vertex1,0);}/*** 添加有向图的边* @param start 开始节点* @param end 结束节点*/public void addDigraphEdge(Vertex start,Vertex end) {//因为是有向图,所以只有一条边addEdgeByVertex(start,end,0);}/*** 添加一条由start-->end的边** @param start* @param end* @param weight 权重未0表示无向图或者有向图,部位0表示网*/private void addEdgeByVertex(Vertex start, Vertex end, int weight) {//1、找到第一个顶点Vertex v1 = this.getVertexByValue(start.value);if(v1 == null){v1 = addVertex(start.value);}//2、检查这条边是否已经存在,已经存在就直接报错for (Vertex w : adj(v1)) {if (end.value.equals(w.value)) {System.out.println("边" + start.value + "-->" + end.value + "已经加入,不可以再加入");return;}}//3.添加Edge firstEdge = v1.firstEdge;if (firstEdge == null) {firstEdge = new Edge(end, weight, null);v1.firstEdge = firstEdge;} else {//当前节点变为第一个节点Edge nowEdge = new Edge(end, weight, null);v1.firstEdge = nowEdge;nowEdge.next = firstEdge;}E++;}/*** 计算V节点的度数*/public static int degree(Graph g, int v) {int degree = 0;Edge firstEdge = g.getVertexByIndex(v).firstEdge;while (firstEdge != null) {degree++;firstEdge = firstEdge.next;}return degree;}/*** 计算所有顶点的最大度数*/public static int maxDegree(Graph G) {int max = 0;for (int v = 0; v < G.V(); v++) {if (degree(G, v) > max) {max = degree(G, v);}}return max;}/*** 计算所有顶点的平均度数*/public static int avgDegree(Graph G) {return 2 * G.E() / G.V();}/*** 计算自环的的个数*/public static int numberOfSelfLoops(Graph g) {int count = 0;for (int v = 0; v < g.V(); v++) {for(int w : g.adj(v)){if(v == w){count++;}}}return count / 2;   //每条边都被记过两次}/*** 得到跟V节点相邻的所有节点*/public static List<Vertex> adj(Vertex vertex) {List result = new LinkedList();Edge firstEdge = vertex.firstEdge;while (firstEdge != null) {result.add(firstEdge.vertex);firstEdge = firstEdge.next;}return result;}/*** 得到跟V节点相邻的所有节点下标  入参是节点的数组下标*/public List<Integer> adj(int index) {List result = new ArrayList();Edge firstEdge = this.getVertexByIndex(index).firstEdge;while (firstEdge != null) {result.add(firstEdge.vertex.index);firstEdge = firstEdge.next;}return result;}/*** 图的邻接表的字符串表示*/public String toString() {String s = V + " vertices, " + E + " edges\n";for (int v = 0; v < V; v++) {Vertex vertex = this.getVertexByIndex(v);s += vertex.value + ": ";for (Vertex w : adj(vertex)) {s += w.value + "";}s += "\n";}return s;}
}

4.深度优先搜索

4.1 找到以起点s连通的所有顶点,和个数 

实现:

用一个递归方法来遍历所有顶点,在访问一个顶点时:

将它标记为已访问

递归地访问它的所有没有被标记过的邻居顶点

package com.sid.graph;public class DepthFirstSearch {private boolean[] marked;private int count;public DepthFirstSearch(Graph G,int s){marked = new boolean[G.V()];dfs(G,s);}private void dfs(Graph G, int index) {marked[index] = true;count++;for(int w : G.adj(index)){if(!marked[w]){dfs(G,w);}}}public boolean marked(int w ){return marked[w];}public int count(){return count;}
}

4.2深度优先搜索查找图中路径

注意这不一定是最短路径,比如说下面这个例子,查出来的0到1的路径,不是0----1,而是0----2----1 

         

package com.sid.graph;import java.util.Stack;public class DepthFirstPaths {private boolean[] marked;  //这个顶点上调用过dfs()了吗private int[] edgeTo;       //从起点到一个顶点的已知路径上的最后一个顶点  比如S---A---C 则 edgeTo[C]=A  edgeTo[C]其实表示的是谁直接指向C点private final int s;       //起点public DepthFirstPaths(Graph G, int s) {marked = new boolean[G.V()];edgeTo = new int[G.V()];this.s = s;dfs(G, s);}private void dfs(Graph G, int index) {marked[index] = true;for (int w : G.adj(index)) {if (!marked[w]) {edgeTo[w] = index;dfs(G, w);}}}public boolean hasPathTo(int v){  //起点S是否有路径到Vreturn marked[v];}public Iterable<Integer> pathTo(int v){if(!hasPathTo(v)){return null;}Stack<Integer> path = new Stack<Integer>();for(int x = v ; x != s ; x = edgeTo[x]){path.push(x);}path.push(s);return path;}
}

5.广度优先搜索

深度优先搜索得到的路径不仅取决于图的结构,还取决于图的表示和递归调用的性质。

“从S到给定目标的顶点V是否存在一条路径?如果有,找出其中最短的那条”,则需要用广度优先搜索。

实现:

1.使用一个队列来保存所有已经被标记过,但其邻接表还未被检查过的顶点

2.先将起点加入队列,然后重复以下步骤直到队列为空

        取队列中的下一个顶点v并标记它

        将与v相邻的所有未被标记过的顶点加入队列

package com.sid.graph;import java.util.*;public class BreadthFirstPaths {private boolean[] marked;  //这个顶点上调用过dfs()了吗private int[] edgeTo;       //从起点到一个顶点的已知路径上的最后一个顶点  比如S---A---C 则 edgeTo[C]=A  edgeTo[C]其实表示的是谁直接指向C点private final int s;       //起点public BreadthFirstPaths(Graph G, int s) {marked = new boolean[G.V()];edgeTo = new int[G.V()];this.s = s;bfs(G, s);}private void bfs(Graph G, int s) {Queue<Integer> queue = new PriorityQueue<>();marked[s] = true;queue.add(s);while (!queue.isEmpty()){int v = queue.poll();for(int w : G.adj(v)){if(!marked[w]){edgeTo[w] = v;marked[w] = true;queue.add(w);}}}}public boolean hasPathTo(int v){return marked[v];}public Iterable<Integer> pathTo(int v){if(!hasPathTo(v)){return null;}Stack<Integer> path = new Stack<Integer>();for(int x = v ; x != s ; x = edgeTo[x]){path.push(x);}path.push(s);return path;}
}

6.连通分量

无向图G的极大连通子图称为G的连通分量( Connected Component)。

任何连通图的连通分量只有一个,即是其自身,非连通的无向图有多个连通分量。 

实现

使用marked[]数组来寻找一个顶点作为每个连通分量中深度优先搜索的起点。

递归的深度优先搜索第一次调用的参数是顶点0,它会标记所有与0连通的顶点。

然后构造函数中for循环会查找每个没有被标记的顶点,并且递归调用dfs()来标记和它相邻的所有顶点。

使用一个以顶点作为索引的数组id[],将同一个连通分量的顶点和连通分量的标识符关联起来(int 值)。这个数组是的connected()方法的实现变得十分简单。

标识符0会被赋予第一个连通分量中的所有顶点,1会被赋予第二个连通分量中的所有顶点,以此类推。这样所有的标识符都会如API中指定的那样在0到count()-1之间。这个约定使得以子图作为索引的数组成为可能。

例子

最后

id[0]= 0

id[1]= 0

id[2]= 0

id[3]= 0

id[4]= 0

id[5]= 0

id[6]= 0

id[7]= 1

id[8]= 1

id[9]= 2

id[10]= 2

id[11]= 2

id[12]= 2

也就是说count[]的值相同的是一个连通分量,count[]的值不同的节点之间是走不通的。

代码

package com.sid.graph;public class CC {private boolean[] marked;private int[] id;private int count;public CC(Graph 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++;}}}private void dfs(Graph 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;}
}

7.G是无环图吗

使用深度优先处理

如果不存在自环和平行边,就是无环图

package com.sid.graph;public class Cycle {private boolean[] marked;private boolean hasCycle;public Cycle(Graph G){marked = new boolean[G.V()];for(int s = 0 ; s < G.V(); s++){if(!marked[s]){dfs(G,s,s);}}}private void dfs(Graph G, int v , int u){marked[v] = true;for(int w : G.adj(v)){if(!marked[w]){dfs(G,w,v);}else if(w != u){  //A---B 与B相邻的节点肯定有A,我理解的是无向图中他们属于同一条边,不是环。hasCycle = true;}}}public boolean hasCycle(){return hasCycle;}
}

8.G是二分图吗(双色问题)

package com.sid.graph;public class TwoColor {private boolean[] marked;private boolean[] color;private boolean isTowColorable = true;public TwoColor(Graph G){marked = new boolean[G.V()];color = new boolean[G.V()];for(int s = 0 ; s < G.V(); s++){if(!marked[s]){dfs(G,s);}}}private void dfs(Graph G, int v) {marked[v] = true;for (int w : G.adj(v)){if(!marked[w]){color[w] = !color[v];}else if(color[w] == color[v]){isTowColorable = false;return;}}}public boolean isBipartite(){return isTowColorable;}
}

9.符号图

节点里面装的不是数字,而是其他的,比如字符串

 

 

 

 

相关文章:

图----无向图

1.定义 图的定义&#xff1a;图是由一组顶点和一组能够将两个顶点相连的边组成 边&#xff1a;edge 顶点&#xff1a;vertex 连通图&#xff1a;如果从任意一个顶点都存在一条路径到达另外一个任意顶点&#xff0c;我们称这幅图是连通图。 非连通图&#xff1a;由若干连通的…...

【C++1】函数重载,类和对象,引用,/string类,vector容器,类继承和多态,/socket,进程信号

文章目录1.函数重载&#xff1a;writetofile()&#xff0c;Ctrue和false&#xff0c;C0和非02.类和对象&#xff1a;vprintf构造函数&#xff1a;对成员变量初始化析构函数&#xff1a;一个类只有一个&#xff0c;不允许被重载3.引用&#xff1a;C中&取地址&#xff0c;C中…...

JetpackCompose从入门到实战学习笔记8—ConstraintLayout的简单使用

JetpackCompose从入门到实战学习笔记8—ConstraintLayout的简单使用 1.简介&#xff1a; Compose 中的 ConstraintLayout ConstraintLayout 是一种布局&#xff0c;让您可以相对于屏幕上的其他可组合项来放置可组合项。它是一种实用的替代方案&#xff0c;可代替使用多个已嵌…...

Spring Boot 快速入门(绝对经典)

目录 1、理论概述 1.1、什么是Spring Boot? 1.2、Spring Boot的特点 1.3、开发环境 2、实战——创建和配置项目 2.1、Spring Boot项目创建的两种方式 2.1.1、方法一&#xff1a;通过网站构建项目 2.1.2、使用Spring Initializr创建&#xff08;推荐&#xff09; 2.2、…...

golang context上下文

文章目录一、为什么需要context二、context 接口三、Background 方法四、 with 系列函数1、WithCancel 方法2、WithDeadline 方法3、WithTimeout 方法4、WithValue 方法五、使用注意事项一、为什么需要context 在 Go http包的Server中&#xff0c;每一个请求在都有一个对应的 …...

Linux---Linux是什么

Linux 便成立的核心网站&#xff1a; http://www.kernel.org Linux是什么 Linux 就是一套操作系统 Linux 就是核心与系统呼叫接口那两层 软件移植&#xff1a;如果能够参考硬件的功能函数并据以修改你的操作系统程序代码&#xff0c; 那经过改版后的操作系统就能够在另一个硬…...

C语言(Tgmath.h库(C99),exit和atexit)

一.Tgmath.h库&#xff08;C99&#xff09; C99标准提供得tgmath.h头文件定义了泛型类型宏。比如在math.h中为一个函数定义了3中类型(float,double和long double)的版本&#xff0c;那么tgmath.h文件就创建一个泛型类型宏&#xff0c;与原来的float,double和long double版本的…...

LeetCode 刷题系列 -- 739. 每日温度

给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。示例 1:输入:temperatures …...

如何生成毕业论文的目录和创建模板

有粉丝同学最近在写毕业论文&#xff0c;其中比较让人恼火的是毕业论文的目录&#xff0c;折腾了几遍没弄好&#xff0c;想让我写个简单地教程&#xff0c;那就来吧。主要分为三步&#xff1a;第一步是从模板里面提取标题的样式&#xff0c;第二步是对自己的论文使用设置好的标…...

新来的23岁软件测试员上来秀了波操作,把几个老员工看傻了

春招了&#xff0c;公司来了个小伙子&#xff0c;一看简历&#xff0c;嘿&#xff1f;22岁&#xff0c;这不刚毕业的小毛孩子嘛&#xff0c;结果没想到人家上来就把现有项目的性能优化了一遍&#xff0c;给公司节省了一半的成本&#xff0c;这种“王炸”打法&#xff0c;直接给…...

Window10开放某个端口

需求&#xff1a;由于防火墙原因&#xff0c;开放某个端口:如9999 在开始那里搜索防火墙-进入防火墙 第一步&#xff1a;核实是否启动了防火墙&#xff0c;之后进行 第二步&#xff1a;点击“高级设置”&#xff0c;→“入站规则”→“新建规则”→“端口”→ “下一步” …...

进阶7 分页查询

进阶7 分页查询&#xff01;&#xff01;&#xff01; 目录概述练习题概述 应用场景&#xff1a;当要显示的数据一页显示不全&#xff0c;需要分页提交SQL请求 语法&#xff1a; select 查询列表 from 表名 【join type join 表2 on 连接条件 where 筛选条件 group by 分组字段…...

利用升序定时器链表处理非活动连接

参考自游双《Linux高性能服务器编程》 背景 服务器同常需要定期处理非活动连接&#xff1a;给客户发一个重连请求&#xff0c;或关闭该连接&#xff0c;或者其他。我们可以通过使用升序定时器链表处理非活动连接&#xff0c;下面的代码利用alarm函数周期性的触发SIGALRM信号&a…...

MySQL 开发规范

一、数据库命名规范所有数据对象名称必须小写 :​​db_user​​禁止使用MySQL 保留关键字&#xff0c;若是则引用 临时表以​​tmp_​​​ 开头&#xff0c;备份表以​​bak_​​ 开头并以时间戳结尾所有存储相同数据的列名和列类型必须一致二、数据库基本设计规范​​1、MySQL…...

【C语言进阶】预处理与程序环境

目录一.详解编译与链接1.前言2.翻译环境3.剖析编译过程4.运行环境二.预处理详解1.预定义符号2.剖析#define(1).定义标识符(2).定义宏(3).替换规则(4).#和##(5).宏与函数的对比(6).#undef3.条件编译4.文件包含(1).头文件包含的方式(2).嵌套文件包含一.详解编译与链接 1.前言 在…...

【Docker知识】将环境变量传递到容器

一、说明 程序通常通过与软件捆绑在一起的配置来控制操作&#xff0c;环境变量允许用户在运行时设置它们。但是&#xff0c;在 Docker 容器中运行进程会使事情变得复杂&#xff0c;那么如何将环境变量传递给容器呢&#xff1f;下面介绍若干个传递办法。 二、环境变量有何用途 环…...

Allegro如何更改铜皮显示密度操作指导

Allegro如何更改铜皮显示密度操作指导 用Allegro做PCB设计的时候,铜皮正常显示模式如下图 铜皮的密度是基本填充满的,Allegro支持更改铜皮的显示密度 如下图 如何更改密度,具体操作如下 点击setup...

ThinkPHP5酒店预订管理系统

有需要请私信或看评论链接哦 可远程调试 ThinkPHP5酒店预订管理系统一 介绍 此酒店预订管理系统基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;采用了ueditor富文本编辑器。系统角色分为用户&#xff0c;员工和管理员。用户可注册登录并预订酒店和评论等&#xff…...

【MySQL】MyCat分库分表分片规则配置详解与实战(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建工设优化。文章内容兼具广度深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于知名金融公…...

OpenWrt路由器设置域名动态解析手把手教程

文章目录0、前言1、准备工作2、详细步骤2.1、OpenWrt路由器软件包安装2.2、防火墙放行入站数据&#xff08;修改为“接受”并保存应用&#xff09;2.3、域名解析服务商对域名的解析设置2.4、路由器中动态域名插件的设置0、前言 因为一直用着内网穿透&#xff08;zerotier或者是…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...