一文搞定图

常见类型与术语

图的表示

邻接矩阵

邻接表

基础操作

基于邻接矩阵的实现

基于邻接表的实现

遍历

广度优先

深度优先


是一种非线性数据结构,由 顶点 组成。
相较于线性关系的链表和分治关系的树,网络关系的图自由度更高

常见类型与术语

根据边是否具有方向,可分为
无向图:
有向图:
根据所有顶点是否连通,可分为
连通图:
非连通图:
根据是否 为边添加“权重”变量,可分为
无权图:
有权图:
常用术语:
邻接:当两顶点之间存在边相连时,称这两顶点“邻接”。
路径:从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径”。
:一个顶点拥有的边数。对于有向图, 入度 表示有多少条边指向该顶点, 出度
表示有多少条边从该顶点指出。

图的表示

邻接矩阵

这个图的邻接矩阵为:

邻接表

这个图的邻接表为:

基础操作

基于邻接矩阵的实现

import java.util.ArrayList;
import java.util.List;/* 基于邻接矩阵实现的无向图类 */
class GraphAdjMat {private List<Integer> vertices; // 顶点列表,元素代表“顶点值”,索引代表“顶点索引”private int[][] adjMat; // 邻接矩阵,行列索引对应“顶点索引”/* 构造方法 */public GraphAdjMat(int[] vertices, int[][] edges) {this.vertices = new ArrayList<>();this.adjMat = new int[vertices.length][vertices.length]; // 初始化邻接矩阵// 添加顶点for (int val : vertices) {addVertex(val);}// 添加边for (int[] e : edges) {addEdge(e[0], e[1]);}}/* 获取顶点数量 */public int size() {return vertices.size();}/* 添加顶点 */public void addVertex(int val) {vertices.add(val);// 扩展邻接矩阵int n = size();int[][] newAdjMat = new int[n][n];// 复制原有邻接矩阵的内容for (int i = 0; i < n - 1; i++) {System.arraycopy(adjMat[i], 0, newAdjMat[i], 0, n - 1);}// 设置新顶点的邻接关系为0for (int i = 0; i < n; i++) {newAdjMat[i][n - 1] = 0; // 新列newAdjMat[n - 1][i] = 0; // 新行}adjMat = newAdjMat; // 更新邻接矩阵引用}/* 删除顶点 */public void removeVertex(int index) {if (index >= size()) {throw new IndexOutOfBoundsException();}// 在顶点列表中移除索引 index 的顶点vertices.remove(index);int n = size();int[][] newAdjMat = new int[n - 1][n - 1];for (int i = 0, newRow = 0; i < n; i++) {if (i != index) {for (int j = 0, newCol = 0; j < n; j++) {if (j != index) {newAdjMat[newRow][newCol++] = adjMat[i][j]; // 复制不包含被删除顶点的行列}}newRow++;}}adjMat = newAdjMat; // 更新邻接矩阵引用}/* 添加边 */// 参数 i, j 对应 vertices 元素索引public void addEdge(int i, int j) {// 索引越界与相等处理if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {throw new IndexOutOfBoundsException();}// 在无向图中,邻接矩阵关于主对角线对称adjMat[i][j] = 1;adjMat[j][i] = 1;}/* 删除边 */// 参数 i, j 对应 vertices 元素索引public void removeEdge(int i, int j) {// 索引越界与相等处理if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {throw new IndexOutOfBoundsException();}adjMat[i][j] = 0;adjMat[j][i] = 0;}/* 打印邻接矩阵 */public void print() {System.out.print("顶点列表 = ");System.out.println(vertices);System.out.println("邻接矩阵 =");for (int[] row : adjMat) {for (int val : row) {System.out.print(val + " ");}System.out.println();}}
}

主要功能

  1. 添加顶点:增加新的顶点并扩展邻接矩阵。
  2. 删除顶点:移除指定索引的顶点和对应的邻接关系。
  3. 添加边:在邻接矩阵中设置两个顶点之间的边。
  4. 删除边:移除两个顶点之间的边。
  5. 打印邻接矩阵:以易于阅读的格式输出邻接矩阵。

基于邻接表的实现

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/* 顶点类 */
class Vertex {int val; // 顶点值public Vertex(int val) {this.val = val;}// 重写 equals 和 hashCode,方便在 Map 中使用。@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (!(obj instanceof Vertex)) return false;Vertex other = (Vertex) obj;return this.val == other.val;}@Overridepublic int hashCode() {return Integer.hashCode(val);}
}/* 基于邻接表实现的无向图类 */
class GraphAdjList {// 邻接表,key:顶点,value:该顶点的所有邻接顶点Map<Vertex, List<Vertex>> adjList;/* 构造方法 */public GraphAdjList(Vertex[][] edges) {this.adjList = new HashMap<>();// 添加所有顶点和边for (Vertex[] edge : edges) {addVertex(edge[0]);addVertex(edge[1]);addEdge(edge[0], edge[1]);}}/* 获取顶点数量 */public int size() {return adjList.size();}/* 添加边 */public void addEdge(Vertex vet1, Vertex vet2) {if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1.equals(vet2)) {throw new IllegalArgumentException();}// 添加边 vet1 - vet2adjList.get(vet1).add(vet2);adjList.get(vet2).add(vet1);}/* 删除边 */public void removeEdge(Vertex vet1, Vertex vet2) {if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1.equals(vet2)) {throw new IllegalArgumentException();}// 删除边 vet1 - vet2adjList.get(vet1).remove(vet2);adjList.get(vet2).remove(vet1);}/* 添加顶点 */public void addVertex(Vertex vet) {if (!adjList.containsKey(vet)) {// 在邻接表中添加一个新链表adjList.put(vet, new ArrayList<>());}}/* 删除顶点 */public void removeVertex(Vertex vet) {if (!adjList.containsKey(vet)) {throw new IllegalArgumentException();}// 在邻接表中删除顶点 vet 对应的链表adjList.remove(vet);// 遍历其他顶点的链表,删除所有包含 vet 的边for (List<Vertex> list : adjList.values()) {list.remove(vet);}}/* 打印邻接表 */public void print() {System.out.println("邻接表 =");for (Map.Entry<Vertex, List<Vertex>> pair : adjList.entrySet()) {List<Integer> tmp = new ArrayList<>();for (Vertex vertex : pair.getValue()) {tmp.add(vertex.val);}System.out.println(pair.getKey().val + ": " + tmp + ",");}}
}// 示例使用
class Main {public static void main(String[] args) {Vertex v1 = new Vertex(1);Vertex v2 = new Vertex(2);Vertex v3 = new Vertex(3);Vertex[][] edges = {{v1, v2}, {v2, v3}, {v1, v3}};GraphAdjList graph = new GraphAdjList(edges);graph.print();}
}

这个类实现了基于邻接表的无向图,包括了添加、删除顶点和边的功能,并且重写了 Vertex 类的 equals 和 hashCode 方法,以便在 HashMap 中正确使用。打印功能将输出每个顶点及其邻接顶点列表。

遍历

广度优先

广度优先遍历是一种由近及远的遍历方式,从某个节点出发,始终优先访问距离最近的顶点,并一层层向外 扩张
/* 广度优先遍历 */
List<Integer> graphBFS(GraphAdjMat graph, int startIdx) {// 顶点遍历序列List<Integer> res = new ArrayList<>();// 哈希集,用于记录已被访问过的顶点Set<Integer> visited = new HashSet<>();visited.add(startIdx); // 将起始顶点标记为已访问// 队列用于实现 BFSQueue<Integer> que = new LinkedList<>();que.offer(startIdx); // 将起始顶点入队// 以顶点 startIdx 为起点,循环直至访问完所有顶点while (!que.isEmpty()) {int idx = que.poll(); // 队首顶点出队res.add(graph.vertices.get(idx)); // 记录访问顶点// 遍历该顶点的所有邻接顶点for (int j = 0; j < graph.size(); j++) {if (graph.adjMat[idx][j] == 1 && !visited.contains(j)) { // 判断是否相邻且未访问que.offer(j); // 只入队未访问的顶点visited.add(j); // 标记该顶点已被访问}}}// 返回顶点遍历序列return res;
}

主要功能

  1. 输入参数:接收一个GraphAdjMat对象和起始顶点的索引。
  2. 结果列表:使用一个列表res来记录访问的顶点。
  3. 访问记录:使用一个哈希集visited来记录已经访问过的顶点,避免重复访问。
  4. 队列实现BFS:使用Queue来按层次遍历图的顶点。

注意事项

  • 确保在构造图时,已知起始顶点的索引。
  • 广度优先遍历的结果将返回按照层次顺序访问的顶点,适合用于查找最短路径或层级关系等应用场合。

深度优先

深度优先遍历是一种优先走到底、无路可走再回头的遍历方式
/* 深度优先遍历辅助函数 */
void dfs(GraphAdjMat graph, Set<Integer> visited, List<Integer> res, int index) {res.add(graph.vertices.get(index)); // 记录访问顶点visited.add(index); // 标记该顶点已被访问// 遍历该顶点的所有邻接顶点for (int j = 0; j < graph.size(); j++) {if (graph.adjMat[index][j] == 1 && !visited.contains(j)) { // 判断是否相邻且未访问dfs(graph, visited, res, j); // 递归访问邻接顶点}}
}/* 深度优先遍历 */
// 使用邻接矩阵表示图,以便获取指定顶点的所有邻接顶点
List<Integer> graphDFS(GraphAdjMat graph, int startIdx) {// 顶点遍历序列List<Integer> res = new ArrayList<>();// 哈希表,用于记录已被访问过的顶点Set<Integer> visited = new HashSet<>();// 调用辅助函数进行深度优先遍历dfs(graph, visited, res, startIdx);return res;
}

主要功能

  1. 辅助函数 dfs

    • 该函数负责递归访问图中的顶点。
    • 记录当前顶点并将其标记为已访问。
    • 遍历所有邻接的顶点,如果相邻顶点未被访问,则递归调用 dfs
  2. 主函数 graphDFS

    • 接收一个 GraphAdjMat 对象和起始顶点的索引。
    • 初始化结果列表 res 和已访问顶点集合 visited
    • 调用 dfs 辅助函数开始深度优先遍历并返回最终的访问顺序。

注意事项

  • 确保在构造图时已知起始顶点的索引。
  • 深度优先遍历适合用于搜索路径、分析连通性等场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/56700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初探Vue前端框架

文章目录 简介什么是Vue概述优势MVVM框架 Vue的特性数据驱动视图双向数据绑定指令插件 Vue的版本版本概述新版本Vue 3Vue 3新特性UI组件库UI组件库概述常用UI组件库 安装Vue安装Vue查看Vue版本 实例利用Vue命令创建Vue项目切换工作目录安装vue-cli脚手架创建Vue项目启动Vue项目…

实战-任意文件下载

实战-任意文件下载 1、开局 开局一个弱口令&#xff0c;正常来讲我们一般是弱口令或者sql&#xff0c;或者未授权 那么这次运气比较好&#xff0c;直接弱口令进去了 直接访问看看有没有功能点&#xff0c;正常做测试我们一定要先找功能点 发现一个文件上传点&#xff0c;不…

Find My平板键盘|苹果Find My技术与键盘结合,智能防丢,全球定位

‌平板键盘的主要用途包括提高输入效率、支持轻量化办公、提供丰富的文本编辑功能以及快捷操作。相比于直接在屏幕上打字&#xff0c;使用键盘可以显著提升输入速度&#xff0c;减少输入错误&#xff0c;特别是对于需要大量文字输入的场景&#xff0c;如写作、记录笔记等‌。平…

擎创科技声明

近日&#xff0c;我司陆续接到求职者反映&#xff0c;有自称是擎创科技招聘人员&#xff0c;冒用“上海擎创信息技术有限公司”名义&#xff0c;用“126.com”的邮箱向求职者发布招聘信息&#xff0c;要求用户下载注册APP&#xff0c;进行在线测评。 对此&#xff0c;我司郑重…

使用 Flask 实现简单的登录注册功能

目录 1. 引言 2. 环境准备 3. 数据库设置 4. Flask 应用基本配置 5. 实现用户注册 6. 实现用户登录 7. 路由配置 8. 创建前端页面 9. 结论 1. 引言 在这篇文章中&#xff0c;我们将使用 Flask 框架创建一个简单的登录和注册系统。Flask 是一个轻量级的 Python Web 框架…

web网站搭建(静态)

准备工作&#xff1a; 关闭防火墙&#xff1a; [rootlocalhost ~]# systemctl disable --now firewalld 修改enforce为permissive [rootlocalhost ~]# setenforce 0 [rootlocalhost ~]# geten getenforce getent [rootlocalhost ~]# getenforce Permissive 重启服务 [rootloca…

AUTOSAR CP 中 BswM 模块功能与使用介绍(2/2)

三、 AUTOSAR BswM 模块详解及 ARXML 示例 BswM 模块的主要功能 BswM&#xff08;Basic Software Mode Manager&#xff09;模块在 AUTOSAR 架构中扮演着模式管理的核心角色。它负责管理车辆的各种模式&#xff08;如启动、运行、停车等&#xff09;&#xff0c;并根据不同的…

网络搜索引擎Shodan(1)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shodan(1)_哔哩哔哩_bilibili 本文主要讲解网络搜索引擎Shodan的一些用法&#xff08;host和search这两个命令&#xff09;。 Shodan 是一个网络…

智创 AI 新视界 -- 探秘 AIGC 中的生成对抗网络(GAN)应用

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【云原生】Kubernets1.29部署StorageClass-NFS作为存储类,动态创建pvc(已存在NFS服务端)

文章目录 在写redis集群搭建的时候,有提到过使用nfs做storageclass,那时候kubernetes是1.20版本,https://dongweizhen.blog.csdn.net/article/details/130651727 现在使用的是kubernetes 1.29版本,根据之前的修改方式并未生效,反而提示:Error: invalid argument "Re…

docker 单节点arm架构服务器安装zookeeper、kafka并测试通信

kafka、zookeeper常用镜像介绍 kafka和zookeeper常见的镜像有以下三个&#xff1a;wurstmeister/zookeeper、kafka、confluentinc/cp-zookeeper、cp-kafka 和 bitnami/zookeeper、kafka。 wurstmeister/xxx: 由wurstmeister团队维护&#xff0c;提供的镜像适用于开发和测试环…

Termius工具在MAC的使用出现的问题:

Termius工具在MAC的使用出现的问题&#xff1a; 在使用SFTP时&#xff0c;出现不了本地的文件的位置 解决方案&#xff1a; 在Apple store下载的使用不了LOCAL SFTP&#xff0c; 需要在网页上进行下载才可以&#xff1a; 官网下载地址&#xff1a;https://termius.com/down…

CentOS 修改服务器登录密码的完整指南

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

缓存池(对象池)使用

框架介绍 对象池的实现是为了优化内存管理和提升性能&#xff0c;尤其是在创建和销毁大量对象时&#xff0c;通过复用已经创建的对象来减少垃圾回收的负担。 实现概述 开放公共方法 记忆已更新 这个对象池的实现是为了优化内存管理和提升性能&#xff0c;尤其是在创建和销…

中国在世界上知名度最高的人物颜廷利:圣人学府-效贤馆互爱天下

中国在世界上知名度最高的人物颜廷利先生在创立效贤馆时&#xff0c;秉持着以下几方面的理念和愿景&#xff1a; 1.传承国学精髓&#xff1a;全世界知名度最高的人颜廷利先生深感国学作为中国传统文化的瑰宝&#xff0c;蕴含着丰富的智慧和哲理。因此&#xff0c;他希望通过效贤…

LINUX1.2

1.一切都是一个文件 &#xff08;硬盘&#xff09; 2.系统小型 轻量型&#xff0c;300个包 3.避免令人困惑的用户界面 ------------------> 就是没有复杂的图形界面 4.不在乎后缀名&#xff0c;有没有都无所谓&#xff0c;不是通过后缀名来定义文件的类型&#xff08;win…

NSSCTF刷题篇web部分

源码泄露 [FSCTF 2023]寻找蛛丝马迹 这个源码泄露&#xff0c;可以记录一下&#xff0c;涉及的知识点比较多 打开环境 查看源码&#xff0c; 第一段flag 乱码&#xff0c;恢复一下 乱码恢复网站&#xff1a;乱码恢复 (mytju.com) 剩下的就只说方法 http://node4.anna.nss…

Python爬虫教程:从入门到精通

Python爬虫教程&#xff1a;从入门到精通 前言 在信息爆炸的时代&#xff0c;数据是最宝贵的资源之一。Python作为一种简洁而强大的编程语言&#xff0c;因其丰富的库和框架&#xff0c;成为了数据爬取的首选工具。本文将带您深入了解Python爬虫的基本概念、实用技巧以及应用…

Linux中安装配置SQLite3,并实现C语言与SQLite3的交互。

前言 SQLite 是一个软件库&#xff0c;实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。本次实验介绍在Linux上实现C语言和SQLite3的交互&#xff0c;利用C语言编写相关语句&#xff0c;连接数据库、操作数…

Cout输出应用举例

Cout输出应用 在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <stdlib.h> //使能exit(); #include <sstream> #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和res…