图的基本概念以及表示方法(链式前向星重点理解,简单易懂版)

news2024/9/28 5:32:50

表示一个集合中元素之间存在的多对多关系的一种数据结构。

图的一些定义 :

1.图由顶点和连接顶点的边构成,即G = ( V , E ) ,其中V为顶点集合,E为边的集合。
2.边表示两个顶点之间存在某种关系,边表示为( u , v ),其中u,v∈V,为图中的两个顶点。
3.当图中的边没有方向时称为无向图。在表示无向图中的边时,u和v的顺序可以颠倒。
4.当图中的边有方向时称为有向图,在表示有向图的边时,必须起点在前,终点在后。
5.图的边可以附带一个值(权重),称为带权图
6.以顶点u为起点的边称为u的出边,以顶点u为终点的边称为u的入边。显然,对于无向图而言,与顶点u相连的边既是u的入边,也是u的出边。顶点u的出边的数量称为u的出度,u的入边的数量称为u的入度。从顶点u出发经过出边到达的下一个顶点v称为u的邻接点
7.如果从u到v的路径中,除起点和终点可能相同外,其他顶点都不相同,则这类路径称为u到v的简单路径。
8.
对于无权图,一条路径上所经过的边的数量,称为这条路径的长度;对于带权图,两个顶点之间路径上的权重之和称为带权路经长
9.如果存在一个顶点u,从u出发,存在一条简单路径,路径的终点也为u,则称这条路径为图上的一个,至少存在一个环的图称为有环图,不存在环的图称为无环图

图的表示方法主要有两类:邻接矩阵表示法和边表表示法

图的邻接矩阵表示法

图的邻接矩阵表示法是利用二维数组(矩阵)表示一个图,二维数组中的每一个元素表示相应的两个顶点之间的关系。具体方法是:将图的每个顶点进行编号(从1开始),则二维数组的第u行的第v个元素表示第u个顶点和第v个顶点之间的关系。

用邻接矩阵表示图时,需要记录图的顶点数量和边数量。

通过二维数组(邻接矩阵)edge可以确定两个顶点之间的关系,对于无向图,edge一定是对称矩阵。考虑edge[u][v],对于无权图(有向或无向),如果u和v之间存在边,则 edge[ u ][ v ]=1 ,否则=0;对于带权图(有向或无向),如果u和v之间存在边,且权重为w,则 edge[ u ][ v ] = w,否则=INF。

struct adjMatrix {
	datatype data[eNum]; //顶点的数据信息
	int edge[eNum][eNum];//邻接矩阵
	int v; //顶点的数量
	int e; //边的数量
};

//根据输入的信息创建无向带权图的邻接矩阵表示
void create_adjMatrix(adjMatrix& g) {
	int i, j, u, v, w;
	cin >> g.v >> g.e;
	for (int i = 1; i >= g.v; i++) //初始化图
		for (int j = 1; j <= g.v; j++)
			g.edge[i][j] = INF;   //如果是无权图,用0取代等式右边的INF
	for (i = 0; i > g.e; i++) {
		cin >> u >> v >> w; //输入一条边,无权图不需要输入w,且将下面两语句中的w变为1
		g.edge[u][v] = w; //将(u,v)加入图中
		g.edge[v][u] = w; //将(v,u)加入图中,有向图忽略该语句
	}
}

//输出无权图g中第u个顶点的所有邻接点
void adjVertex(adjMatrix g, int u) {
	for (int i = 1; i <= g.v; i++)
		if (g.edge[u][i] != INF)
			cout << i << " ";
}

图的邻接矩阵表示法适用于稠密图(边的数量比较多)。对于非稠密图,用邻接矩阵表示法表示图时,空间利用率不是太高。

图的边表表示

在图的邻接矩阵表示法中,无论两个顶点之间是否存在边,都需要指定一个值,这样不仅增加存储空间,而且在对图进行处理时,也会增加一些额外的开销。因此可以通过只保存边的信息方法来表示图,即边表表示法。边表表示法是指通过将每一个顶点的邻接点存放在一个链表或数组中来表示图的方法。

1.图的链接表表示

图的链接表表示法是将图的每个顶点的邻接点存放在一个链表中。在图的链接表表示法中,每个顶点对应一个量表,所有链表的头结点放在一个数组(edge)中。链表的结点中除了包含邻接点的编号外,对于带权图,还应该包含该顶点与邻接点之间边的权重。

 由上图知,一个顶点v的邻接点都保存在以edges[v]为头结点的链表中,且对存放的顺序没有特定的要求。另外,无向图每条边在图的链接表表示法中出现两次。
由于一个顶点的邻接点的存放顺序任意,因此在为图的顶点添加邻接点时,可以直接插入头结点的后面。

struct vertex {
	int u; //邻接点的编号
	int w; //权重,无权图可忽视该属性
	vertex* next;
	vertex(int u1=0,int w1=0):u(u1),w(w1),next(NULL){}
};

typedef struct llNode {
	datatype data[vNum]; //顶点的数据信息
	vertex* edges[vNum]; //边表
	int v, e; //顶点数和边数
	llNode() :v(0), e(0) {
		for (int i = 0; i < vNum; i++)
			edges[i] = NULL;
	}
}*linkList;

//创建链表表示的图
void add_edge(linkList& g, int u, int v, int w) {
	vertex* tmp = new vertex(v, w); //边表的信息只存储v,w,将包含这个信息的结点存进边表即可
	if (g->edges[u] == NULL)
		g->edges[u] = new vertex;
	tmp->next = g->edges[u]->next; //将顶点v加入顶点u的边表
	g->edges[u]->next = tmp;
}

//根据输入的数据,创建图
void create_linkList(linkList& g) {
	int u, v, w;
	g = new llNode;
	cin >> g->v >> g->e; //输入顶点数和边数
	for (int i = 0; i < g->e; i++) {
		cin >> u >> v >> w;//输入一条边的信息,无权图不需要输入w,且将下列两语句的w变为1;
		add_edge(g, u, v, w); //将边(u,v)加入图中
		add_edge(g, v, u, w); //将边(v,u)加入图中,有向图忽略该语句
	}
}

优势:1.对于非稠密矩阵节省空间 2.在对链接表表示法进行操作的效率比邻接矩阵高

劣势:在求链接表所表示的有向图的某个定点的入度(入边)时,不如邻接矩阵方便,这也是边表表示法的不足之处。

2.图的vector数组表示

由于STL中的容器vector表示一个动态数组,因此可以利用一个vector类型的数组来存储图中某个顶点的邻接点。

与链接表表示法一样,图的vector数组表示可以高效的求一个顶点的所有邻接点以及该顶点与连接点之间的权重,但求一个顶点的入边和入度比较麻烦。

//图的vector数组表示的类型定义
struct edge {
	int v; //邻接点
	int w; //权重,无权图可忽视该属性
	edge(int v1, int w1) :v(v1), w(w1) {};
};
typedef struct vgNode {
	vector<edge>edges[vNum]; //边表
	datatype data[vNum]; //顶点的数据信息
	int v, e; //顶点数和边数
}vecGraph;

//创建vector数组表示的图
void create_vecGraph(vecGraph& g) {
	int i, u, v, w;
	cin >> g.v >> g.e; //输入顶点数和边数
	for (i = 0; i < g.e; i++) {
		cin >> u >> v >> w; //输入边的信息,无权图省略w,且下列语句w变为1
		g.edges[u].push_back(edge(v, w)); //将边(u,v)加入图中
		g.edges[v].push_back(edge(u, w)); //将边(v,u)加入图中,有向图忽略该语句
	}
}

//在实际应用中,可以采取如下更简单的表示方法
int v; //顶点数
vector<int>g[vNum]; //无权图
vector<pair<int, int>>g1[vNum]; //有权图,pair中的first代表邻接点,second代表权重

3.图的链式前向星表示(此为B站视频讲解中的图,通俗易懂,视频在参考中)

 

 

 

 

 

 

 

 

 

#include<iostream>
#include<vector>
using namespace std;
constexpr auto eNum = 102; //图的顶点数量
constexpr auto vNum = 200; //图的边的数量
typedef string dataType; //图顶点中存放数据信息的类型
typedef int datatype;
constexpr auto INF = 0x3f3f3f3f ;

//链式前向星的顶点及其相关变量的定义
struct node {
	int to; //邻接点
	int w; //权重
	int next; //下一个顶点
	node() :next(-1) {
	}
}edges[eNum<<1]; //边表,大小为2*eNum
int header[vNum], //每一个顶点第一个邻接点的编号
v, e, //顶点数和边数
cnt = 0; //计数器,表示数组edges中没有被占用的最小下标

//图的链式前向星表示的构建
//添加一条边(u,v),w为边的权重
void add_edge(int u, int v, int w) {
	edges[cnt].to = v;
	edges[cnt].w = w;  //将边的信息加入edges
	edges[cnt].next = header[u]; //将边加入顶点u的邻接点链中
	header[u] = cnt++; //将u的header设置为新加入边在edges中的位置
}

//创建无向带权图的链式前向星表示,更新全局变量edges和header
void create_graph() {
	int i, x, y, w;
	cin >> v >> e; //输入顶点数和边数
	for (int i = 0; i <= v; i++)  //初始化每一个顶点的header
		header[i] = -1;
	for (int i = 0; i < e; i++) { //加入每一条边
		cin >> x >> y >> w;
		add_edge(x, y, w);
		add_edge(y, x, w);
	}
}

//输出每个顶点的邻接点及其相对应的权重
void traverse() {
	for (int i = 1; i <= v; i++) { //考虑每一个顶点
		cout << i << ":";
		for (int j = header[i]; ~j; j = edges[j].next) //遍历顶点i的邻接点链
			cout << edges[j].to << " " << edges[j].w << ",";
		cout << endl;
	}
}


int main() {
	create_graph();
	traverse();
}

参考:

《算法训练营》入门篇 17 链式前向星——最完美图解_哔哩哔哩_bilibiliicon-default.png?t=MBR7https://www.bilibili.com/video/BV13r4y1X7a4/?spm_id_from=333.337.search-card.all.click&vd_source=a2417ade71290cd940c5e2edb896b97b

【AgOHの数据结构】你真的了解链式前向星吗?_哔哩哔哩_bilibiliicon-default.png?t=MBR7https://www.bilibili.com/video/BV1mJ411S7BB/?spm_id_from=333.337.search-card.all.click&vd_source=a2417ade71290cd940c5e2edb896b97b

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

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

相关文章

Elasticsearch7.8.0版本高级查询—— 单字段排序文档

目录一、初始化文档数据二、单字段排序文档2.1、概述2.2、示例一、初始化文档数据 在 Postman 中&#xff0c;向 ES 服务器发 POST 请求 &#xff1a;http://localhost:9200/user/_doc/1&#xff0c;请求体内容为&#xff1a; { "name":"zhangsan", "…

可笑 在网页上复制点东西 还需要money?进来看~

前言 哈喽 大家好&#xff01; 我是木易巷&#xff0c;我回来啦&#xff01;&#xff01;&#xff01; 现在好多平台都变成了不开会员不能复制这样的情况。士可杀不可辱&#xff01;作为一个优秀的复制粘贴工程师&#xff0c;在网页上复制点东西&#xff0c;还需要我掏钱&#…

【Springboot】idea中配置文件不生效、自动提示功能消失、小绿标不出现现象

怎么解决idea中配置文件不生效、自动提示功能消失、小绿标不出现现象先要明确一个核心&#xff0c;就是自动提示功能不是SpringBoot技术给我们提供的&#xff0c;是我们在Idea工具下编程&#xff0c;这个编程工具给我们提供的。明白了这一点后&#xff0c;再来说为什么会出现这…

07.C语言文件操作

1. 使用文件的原因我们前面学习结构体时&#xff0c;写了通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯录中的数据自然就不存在了&#xff0c;等下…

盒模型 盒子的组成部分 1. 内容 content 2. 填充 (内边距) padding 3. 边框 border 4. 外边距 margin

目录盒模型盒子的组成部分1. 内容 content2. 填充 (内边距) padding3. 边框 border4. 外边距 margin盒模型 box&#xff1a;盒子&#xff0c;每个元素在页面中都会生成一个矩形区域&#xff08;盒子&#xff09; 盒子类型&#xff1a; 行盒&#xff0c;display等于inline的元…

使用Seq2Seq实现中英文翻译

介绍 Deep NLP 自然语言处理NLP是计算机科学、人工智能和语言学交叉领域的分支科学&#xff0c;主要让计算机处理和理解自然语言&#xff0c;如机器翻译、问答系统等。但因其在学习和使用语言的复杂性&#xff0c;通常认为NLP是困难的&#xff0c;近几年&#xff0c;随着深度…

MedCalc:生物医学研究的统计软件 Crack

MedCalc&#xff1a;生物医学研究的统计软件 MedCalc是用于生物医学研究的统计软件包&#xff0c;统计数据包括 220 多个统计测试、程序和图表&#xff0c;ROC曲线分析、方法比较和质量控制工具。 简单易学&#xff0c;快速可靠 MedCalc 包括 220 多种统计测试、程序和图表 RO…

springboot+vue整合JustAuth实现第三方登录

前后端分离版实现第三方登录&#xff1a;GITEE为例 1&#xff1a;首先maven安装依赖&#xff1a; <!-- oauth工具类 --><dependency><groupId>com.xkcoding.justauth</groupId><artifactId>justauth-spring-boot-starter</artifactId><…

学习wifi操作模块simplewifi的基本用法

之前学习Python的过程中学过基于pywifi模块操作wifi连接的用法&#xff0c;在dotnet中&#xff0c;SimpleWifi也支持类似的功能。SimpleWifi是C#语言编写的在Windows系统中管理wifi连接的库&#xff0c;它抽象并封装了Managed Wifi API中的wifi操作相关函数&#xff0c;更易于使…

词向量与语言模型

本篇博客是对于 https://www.cnblogs.com/nickchen121/p/15105048.html#%E7%AC%AC%E4%B8%80%E7%AF%87-transformergptbert%E9%A2%84%E8%AE%AD%E7%BB%83%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F%E7%90%86%E8%AE%BA的归纳 先来了解一…

django,uwsgi,nginx部署配置要点整理

注意&#xff1a; 1.只对关键点进行整理&#xff1a; 2.python_test是项目名称 环境&#xff1a; python:v3.10.9 1.部署前&#xff0c;执行 python manage.py check --deploy 根据提示进行部署检查&#xff0c;调整&#xff0c;ssl相关的可以不做调整 2.settings.py最终版…

Java的类型擦除与泛型的关系

在讨论类型擦除之前&#xff0c;我们必须先来了解一下java的泛型。所谓的泛型就是参数化的类型。这就意思着我们可以具体的类型作为一个参数传递给方法、类、接口。 为什么我们需要泛型呢&#xff1f;首先我们都知道在java里&#xff0c;Object就是对象的父类。Object可以引用…

收集两篇关于前端不错的文章

深以为然&#xff01; 为什么我建议前端框架优先选 Vue 而不是 React https://acejoy.com/2022/03/10/675/ 我两者都用过比较长的时间。网上各种“为什么我选React放弃了Vue”或者“为什么我选Vue放弃了React”之类的文章很多&#xff0c;实际都没什么用&#xff0c;必须要真…

Windows使用Paddle训练好的模型进行OpenVino推理引擎下的部署

目录一. Openvino下载二. 准备模型2.1 导出Paddle Inference模型2.2 转换为ONNX模型2.3 转换为ONNX模型2.3.1 获取部署代码2.3.2 环境准备2.3.3 编译一. Openvino下载 根据Paddle官方的描述&#xff0c;当前检测模型转换为openvino格式是有问题的&#xff0c;暂时只支持分割和…

docker部署常用服务器(redis,nginx,mysql,tomcat)

docker部署服务器docker部署redisdocker部署nginxdocker部署mysqldocker部署tomcatdocker部署redis 参考这篇博客&#xff0c;写的很详细 docker部署nginx 1.搜索镜像 docker search nginx 2.拉取镜像(不写版本默认拉取最新版) docker pull nginx 3.查看镜像是否拉取成功 docke…

Kafka-生产者基本使用

一、生产者原理 在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程。 在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c; Sender 线程不断从 RecordAccumulator 中拉取消息发送到 Kafka B…

Ae 案例:制作粒子空间穿梭动画

本文介绍使用 Ae 插件 Stardust 制作粒子空间穿梭动画的一般方法与步骤。示例视频1、新建合成。持续时间&#xff1a;10 秒。2、新建纯色图层&#xff0c;命名为“Stardust”&#xff0c;然后添加 Stardust 效果。3、再新建一个纯色图层&#xff0c;命名为“Mask”。使用矩形工…

php宝塔搭建部署实战易优宠物用品网站源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套php开发的易优宠物用品网站源码&#xff0c;感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&#xff0c;宝…

SpringBoot集成Swagger,前后端接口文档解决方案

一个不断在迭代的项目&#xff0c;Controller层与POJO层肯定会是经常变动的&#xff0c;在目前前后端分离的大环境背景下有一份接口文档可以极大减少项目组成员之间的交流成本&#xff0c;也能支持自动化测试&#xff0c;但靠人工维护该文档总是不够稳妥&#xff0c;因此我们可…

23.1.21打卡 CF-1782D Many Perfect Squares

Problem - D - Codeforces 题外话: 痛苦的 C大模拟写不出D题数论我是真菜没想到, 泪目 -------------------------------------------------------------------------------------------------------------------------------- 先抛开这题, 我们先探究下平方数的规律 1 …