【图(1)】:用邻接矩阵和邻接表实现图

目录

一、图的基本概念

二、图的存储结构

1.邻接矩阵

2.邻接表


一、图的基本概念

注意:概念性的文字不列出太多,记不住也不便于理解

图(Graph)是由节点(Node)和边(Edge)组成的数据结构。图可以用来表示对象之间的关系,其中节点表示对象,边表示对象之间的连接或关联。

图的基本概念包括以下几个要素:

  1. 节点:也称为顶点(Vertex),表示图中的对象。节点可以具有属性或标签,用于描述对象的特征。

  2. 边:也称为弧(Arc)或连接(Link),表示节点之间的关系或连接。边可以是有向的(从一个节点指向另一个节点)或无向的(没有方向)。

  3. 权重:边可以带有权重(Weight),表示节点之间的某种度量或距离。权重可以表示关系的强度、路径的长度等。

  4. 邻接:两个节点之间存在一条边,则它们被称为邻接(Adjacent)节点。如果图是有向的,那么邻接节点分为入度邻接节点和出度邻接节点。无向图某顶点的度=入度=出度,有向图某顶点的度=入度+出度。

  5. 路径:路径(Path)是由边连接的节点序列,表示从一个节点到另一个节点的通路。路径的长度可以通过边的数量或权重之和来衡量。

  6. 连通性:图中的节点通过边相互连接,如果任意两个节点之间都存在路径,那么图被称为连通图。如果图中存在不连通的部分,则称为非连通图。

  7. 图的类型:根据边的属性和连接方式,图可以分为有向图(Directed Graph)和无向图(Undirected Graph)。有向图的边具有方向性,无向图的边没有方向。此外,还有其他特殊类型的图,如加权图、带环图等。

不带权值的图:

带权值的图:

简单路径与回路: 若路径上各顶点 v1 v2 v3 vm 均不重复,则称这样的路径为简单路径 若路径上 第一个顶点 v1 和最后一个顶点 vm 重合,则称这样的路径为回路或环。

子图: 设图 G = {V, E} 和图 G1 = {V1 E1} ,若 V1 属于 V E1 属于 E ,则称 G1 G 的子图

 

二、图的存储结构

因为图中既有节点,又有边(节点与节点之间的关系),因此,在图的存储中,只需要保存:节点和边关系即可

1.邻接矩阵

因为节点与节点之间的关系就是连通与否,即为0或者1,因此邻接矩阵(二维数组)即是:先用一个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系。 
注意:大多图的算法题面试题都是基于邻接矩阵的形式,因此邻接矩阵是重点。

拿G1这个图举例, 假设顶点个数为n,邻接矩阵为arr[n][n],arr[i][j]的值就表示权值(无向图则为1),而指向则为i -> j,即i下标对应顶点指向j下标对应的顶点。
无向图的邻接矩阵是对称的第i行(列)元素之和,就是顶点i的度有向图的邻接矩阵则不一定是对称 的,第i行(列)元素之后就是顶点i 的出(入)度
有向带权值图:

用邻接矩阵存储图的优点是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间,并且要求两个节点之间的路径不是很好求。

下面看代码实现(基于无向图G1)

  • printGraph方法用于打印邻接矩阵;
  • 顶点用HashMap存储 顶点-下标 的键值对,使获取下标的时间复杂度达到O(1);
  • addEdge方法表示v1指向v2。
//邻接矩阵
public class GraphByMatrix {private char[] arrayV; //存放顶点private int[][] matrix; //存放权值或者边private boolean isDirect; //是否是有向图private HashMap<Character, Integer> indexMap; //定位顶点对应的下标public GraphByMatrix(int size, boolean isDirect) {arrayV = new char[size];matrix = new int[size][size];this.isDirect = isDirect;indexMap = new HashMap<>();}/*** 初始化** @param array 顶点集合*/public void initArrayV(char[] array) {for (int i = 0; i < array.length; i++) {arrayV[i] = array[i];indexMap.put(array[i], i);}}/*** 给两个顶点的边添加权重** @param v1     顶点1* @param v2     顶点2* @param weight 权值*/public void addEdge(char v1, char v2, int weight) {int index1 = getIndexOfV(v1);int index2 = getIndexOfV(v2);if (index1 == -1 || index2 == -1) {throw new RuntimeException("v1或v2顶点不存在");}matrix[index1][index2] = weight;//无向图则对称位置也设置权重if (!isDirect) {matrix[index2][index1] = weight;}}//获取该顶点对应的下标private int getIndexOfV(char v) {Integer index = indexMap.get(v);return index == null ? -1 : index;//hashMap定位}/*** 获取顶点的度** @param v* @return*/public int getDevOfV(char v) {//1.获取顶点在arrayV的下标int index = getIndexOfV(v);//2.计算该顶点的出度int count = 0;for (int i = 0; i < arrayV.length; i++) {if (matrix[index][i] != 0) {count++;}}//3.如果是有向图,还需要计算顶点的入度if (isDirect) {for (int i = 0; i < arrayV.length; i++) {if (matrix[i][index] != 0) {count++;}}}return count;}public void printGraph() {System.out.print("  ");for (char c : arrayV) {System.out.print(c + " ");}System.out.println();for (int i = 0; i < matrix.length; i++) {System.out.print(arrayV[i] + " ");for (int j = 0; j < matrix[i].length; j++) {System.out.print(matrix[i][j] + " ");}System.out.println();}}
}

代码测试:

    public static void main(String[] args) {GraphByMatrix graphByMatrix = new GraphByMatrix(4, false);char[] array = {'A', 'B', 'C', 'D'};graphByMatrix.initArrayV(array);graphByMatrix.addEdge('A', 'B', 1);graphByMatrix.addEdge('A', 'D', 1);graphByMatrix.addEdge('B', 'A', 1);graphByMatrix.addEdge('B', 'C', 1);graphByMatrix.addEdge('C', 'B', 1);graphByMatrix.addEdge('C', 'D', 1);graphByMatrix.addEdge('D', 'A', 1);graphByMatrix.addEdge('D', 'C', 1);graphByMatrix.printGraph();System.out.println("顶点A的度:" + graphByMatrix.getDevOfV('A'));}

假设无向图(第二参数为false)                              假设有向图(第二参数为true)

 

2.邻接表

邻接表:使用数组表示顶点的集合,使用链表表示边的关系
1. 无向图邻接表存储

注意:无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点vi边链表集 合中结点的数目即可
2. 有向图邻接表存储

注意:有向图中每条边在邻接表中只出现一次,与顶点vi对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dest 取值是i。总结就是看顶点V指向哪些顶点(出度表),加上哪些顶点也指向顶点V(入度表)
import java.util.ArrayList;
import java.util.HashMap;//邻接表
public class GraphByTable {static class Node {public int src; //起点坐标public int dest; //终点坐标public int weight; //权重public Node next;public Node(int src, int dest, int weight) {this.src = src;this.dest = dest;this.weight = weight;}}private ArrayList<Node> edgeList; //保存所有的顶点private char[] arrayV; //顶点数组private boolean isDirect; //是否是有向图private HashMap<Character, Integer> indexMap; //快速定位顶点下标public GraphByTable(int size, boolean isDirect) {arrayV = new char[size];this.isDirect = isDirect;indexMap = new HashMap<>();edgeList = new ArrayList<>(size);//给list添加元素,否则list初始为空for (int i = 0; i < size; i++) {edgeList.add(null);}}public void initArrayV(char[] array) {for (int i = 0; i < array.length; i++) {arrayV[i] = array[i];indexMap.put(array[i], i);}}/*** 给两个顶点的边添加权重** @param v1     顶点1* @param v2     顶点2* @param weight 权值*/public void addEdge(char v1, char v2, int weight) {//1.找出两个顶点在数组中的位置int src = getIndexOfV(v1);int dest = getIndexOfV(v2);addEdgeChild(src, dest, weight); //连通//2.如果是无向图,反方向连通if (!isDirect) {addEdgeChild(dest, src, weight);}}private void addEdgeChild(int src, int dest, int weight) {//获取顶点集合中链表的头节点Node cur = edgeList.get(src);while (cur != null) {//如果当前节点的dest就是要连通的dest,说明已经连通过了if (cur.dest == dest) {return;}cur = cur.next;}//走到这说明顶点还没连通过,进行头插Node node = new Node(src, dest, weight);node.next = edgeList.get(src);edgeList.set(src, node);}private int getIndexOfV(char v) {return indexMap.get(v);}/*** 获取顶点的度** @param v* @return*/public int getDevOfV(char v) {//1.获取顶点的下标,得到链表int index = getIndexOfV(v);Node cur = edgeList.get(index);//2.计算出度(无向图的度就是出度)int count = 0;while (cur != null) {count++;cur = cur.next;}//3.如果是有向图,还要计算顶点的入度if (isDirect) {for (int i = 0; i < edgeList.size(); i++) {//出度的链表不能计算进去if (i != index) {cur = edgeList.get(i);while (cur != null) {//cur的dest为当前顶点下标,就是当前顶点的入度if (cur.dest == index) {count++;}cur = cur.next;}}}}return count;}public void printGraph() {for (int i = 0; i < edgeList.size(); i++) {System.out.print(arrayV[i] + " -> ");Node cur = edgeList.get(i);while (cur != null) {System.out.print(cur.dest + " -> ");cur = cur.next;}System.out.println();}}public static void main(String[] args) {GraphByTable graphByTable = new GraphByTable(4, true);char[] array = {'A', 'B', 'C', 'D'};graphByTable.initArrayV(array);graphByTable.addEdge('A', 'B', 1);graphByTable.addEdge('A', 'D', 1);graphByTable.addEdge('B', 'A', 1);graphByTable.addEdge('B', 'C', 1);graphByTable.addEdge('C', 'B', 1);graphByTable.addEdge('C', 'D', 1);graphByTable.addEdge('D', 'A', 1);graphByTable.addEdge('D', 'C', 1);graphByTable.printGraph();System.out.println(graphByTable.getDevOfV('A'));}
}

测试图仍为前面的无向图G1

假设无向图:                                                       有向图:

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

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

相关文章

Vue 监听器:让你的应用实时响应变化

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

CSS居中对齐 (水平垂直居中对齐)

方案一&#xff1a;flex布局【推荐】 给容器添加样式 display: flex; justify-content: center; align-items: center; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" conte…

第三百九十六回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何混合选择多个图片和视频文件"相关的内容&#xff0c;本章回中将介绍显示Snackbar的另外一种方法.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1…

算法-贪心-122. 糖果传递

题目 有 n个小朋友坐成一圈&#xff0c;每人有 a[i]个糖果。 每人只能给左右两人传递糖果。 每人每次传递一个糖果代价为 1。 求使所有人获得均等糖果的最小代价。 输入格式 第一行输入一个正整数 n&#xff0c;表示小朋友的个数。 接下来 n 行&#xff0c;每行一个整数…

【组合递归回溯】【StringBuilder】Leetcode 17. 电话号码的字母组合

【组合递归回溯】【StringBuilde】Leetcode 17. 电话号码的字母组合 StringBulider常用方法&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;17…

JavaScript实现通过键盘弹钢琴的效果

本片文章通过触发键盘事件来触发对应的音乐&#xff0c;而且给页面添加了渐变的active类名&#xff0c;通过触发不同的鼠标事件&#xff0c;然后active类移动来实现按下钢琴键的视觉效果。 关键代码&#xff1a; <!DOCTYPE html> <html lang"en"><h…

十堰网站建设公司华想科技具有10年的网站制作经验

2018年已经结束了。 华翔科技收到了很多客户的咨询&#xff0c;他们都有一个共同的问题&#xff1a;建一个网站需要多少钱&#xff1f; 但是&#xff0c;我们都会问&#xff1a;您有什么具体需求吗&#xff1f; 大多数人的答案是否定的&#xff0c;他们只是想打听一下价格。 十…

嵌入式3-11

1、整理思维导图 2、尝试学生结构体数组&#xff0c;完成成员的输入&#xff0c;以成绩为条件完成对学生成员的冒泡排序并输出&#xff08;全部在主函数内完成&#xff09; #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.…

25改考408最新资讯!拷贝

东北大学 东北大学计算机考研全面改考408 东北大学计算机学院官网&#xff1a;http://www.cse.neu.edu.cn/6274/list.htm 东北大学计算机考研全面改考408 公告原文 东北大学计算机科学与工程学院关于调整2025年硕士研究生招生计算机科学与技术、计算机技术、人工智能专业初试…

【JAVA类】利用接口的多继承实现———图书管理系统【附源码】

引言 在我们学习了一些java的基础语法之后&#xff0c;需要把这些知识点可以串起来&#xff0c;这里使用一个简单的小项目可以很好的帮助我们牢记这些知识点&#xff0c;今天就带大家学习一个有关java的小项目&#xff0c;很多学校也经常把这个项目作为他们的课程设计——经典的…

从零学习Linux操作系统 第三十二部分 Ansible中的变量及加密

一、变量的基本设定及使用方式 变量命名&#xff08;与shell相同&#xff09;&#xff1a; 只能包含数字&#xff0c;下划线&#xff0c;字母 只能用下划线或字母开头 .变量级别&#xff1a; 全局从命令行或配置文件中设定的paly:在play和相关结构中设定的主机:由清单&…

基于 Win Server 2008 复现 IPC$ 漏洞

写在前面 本篇博客演示了使用 winXP&#xff08;配合部分 win10 的命令&#xff09;对 win server 2008 的 IPC$ 漏洞进行内网渗透&#xff0c;原本的实验是要求使用 win server 2003&#xff0c;使用 win server 2003 可以规避掉很多下面存在的问题&#xff0c;建议大家使用 …

如何在Linux部署FastDFS文件服务并实现无公网IP远程访问内网文件——“cpolar内网穿透”

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

TCP多线程模型、IO模型(select、poll、epoll)

我要成为嵌入式高手之3月11日Linux高编第十九天&#xff01;&#xff01; ———————————————————————————— TCP并发模型 一、TCP多线程模型&#xff1a; 缺点&#xff1a;创建线程会带来资源开销&#xff0c;能够现的并发量比较有限 二、IO模型&…

【PHP】PHP通过串口与硬件通讯,向硬件设备发送数据并接收硬件返回的数据

一、前言 之前写过两篇PHP实现与硬件串口交互的文章&#xff0c;一篇是【PHP】PHP实现与硬件串口交互&#xff0c;接收硬件发送的实时数据&#xff08;上&#xff09;_php串口通信-CSDN博客&#xff0c;另一篇是【PHP】PHP实现与硬件串口交互&#xff0c;向硬件设备发送指令数…

HarmonyOS NEXT应用开发之图片缩放效果实现

腾讯T10级高工技术&#xff0c;安卓全套VIP课程全网免费送&#xff1a;https://docs.qq.com/doc/DSG1vYnRxSElnU3hE 学习鸿蒙开发势在必行。鸿蒙开发可参考学习文档&#xff1a;https://qr21.cn/FV7h05 介绍 图片预览在应用开发中是一种常见场景&#xff0c;在诸如QQ、微信、…

Facebook商城号为什么被封?如何防封?

由于Facebook商城的高利润空间&#xff0c;越来越多的跨境电商商家注意到它的存在。Facebook作为全球最大、用户量最大的社媒平台&#xff0c;同时也孕育了一个巨大的商业生态&#xff0c;包括广告投放、商城交易等。依托背后的大流量&#xff0c;Facebook商城起号较快&#xf…

GPU,一统天下

三十年前&#xff0c;CPU 和其他专用处理器几乎处理所有计算任务。那个时代的显卡有助于加快 Windows 和应用程序中 2D 形状的绘制速度&#xff0c;但没有其他用途。 快进到今天&#xff0c;GPU 已经成为业界最具主导地位的芯片之一。 但具有讽刺意味的是&#xff0c;图形芯片…

ETCD入门

目录 一、简介 1. etcd是什么 2. 特点 3. 使用场景 4. 关键字 5. 工作原理 6. 获取 二、安装 1. etcd安装前的介绍 2. 安装 3. 启动 4. 创建一个etcd服务 三、ETCD的使用 一、简介 1. etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是…

Retrofit

1.导入依赖 //Retrofit 核心库implementation("com.squareup.retrofit2:retrofit:2.9.0")//响应数据自动序列化//JSONimplementation("com.squareup.retrofit2:converter-gson:2.9.0")//String类型implementation("com.squareup.retrofit2:converter…