图——“多对多”的逻辑结构

目录

1.什么是图?

图包含:

 2.图的基本术语

无向图:

有向图:

权重:边上的数字

度:

邻接点:

完全图:

 3.图的抽象数据类型定义

4.怎么在程序中表示一个图? 

邻接矩阵表示法(稠密图) 

邻接表表示法(稀疏图) 

 5.图的建立C语言实现

 邻接矩阵式

 邻接表式


1.什么是图?

表示“多对多”的关系。

其实线性表和树可以看作简化的图。

 

图包含:

一组顶点:通常用V(Vertex)表示顶点集合

一组边:通常用E(Edge)表示边的集合

        ●边是顶点对:( v , w )∈ E ,其中 v , w ∈ V

        ●有向边< v , w >表示从v指向w的边(单行线)

        ●不考虑重边和自回路

 2.图的基本术语

无向图:

有向图:

权重:边上的数字

网络:带权重的有向/无向图

度:

        对于无向图:一个点所有的边数。

        对于有向图:从该点出发的边数叫“出度”,指向该点的边数叫“入度”

邻接点:

有边直接相连的顶点

完全图:

完全图是一个简单的无向图,其中每对不同的顶点之间都恰连有一条边相连。

 3.图的抽象数据类型定义

名字:图(Graph)

数据对象集:G( V, E )由一个非空的有限顶点集合V和一个有限边集合E组成。

操作集合:对于任意图G∈Graph,以及v∈V,e∈E 。

Graph Create():建立并返回空图;

Graph InsertVertex(Graph G , Vertex v):将v插入G;

Graph InsertEdge(Graph G , Edge e):将e挿入G;

void DES( Graph G  , Vertex v ):从顶点v出发深度优先遍历图G;

void BES( Graph G  , Vertex v ):从顶点v出发宽度优先遍历图G;

void ShortestPath( Graph G, Vertex v ,int Dist [ ] ): 计算图G中顶点v到任意其他顶点的最短距离;

void MST( GraphG ):计算图G的最小生成树;

4.怎么在程序中表示一个图? 

“并不是只有以下两种方法,而是取决于图的特点来选取表示方法。” 

邻接矩阵表示法(稠密图) 

         图的邻接矩阵表示法就是开一个二维数组G[ i ][ j ],凡是两个顶点(v1,v2)之间有边时就将G[v1][v2]的值置为1。否则为0

: 对于无向图 G[v1][v2]=1 且 G[v2][v1]=1

 

        对于有向图 G[v1][v2]=1 但 G[v2][v1]=0

 

图示:

结构体定义:

typedef struct GNode *PtrToGNode;
struct GNode {WeightType G[MaxVertexNum][MaxVertexNum];int Nv; /* 顶点数 */int Ne; /* 边数 */DataType Data[MaxVertexNum]; /* 存顶点的数据 */
}
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */

 优点:

 直观、简单、好理解
方便检查任意一对顶点间是否存在边
方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
方便计算任一顶点的“度”(从该点发出的边数为“出 度”,指向该点的边数为“入度”)
        -无向图:对应行(或列)非 0元素的个数
        -有向图:对应行非 0元素的个数是“出度”;对应列非 0元素的个数是“入度”

缺点:

浪费空间 —— 存稀疏图(点很多而边很少)有大量无效元素
对稠密图(特别是完全图)还是很合算的
浪费时间 —— 统计稀疏图中一共有多少条边 

邻接表表示法(稀疏图) 

 邻接表:G[N]为指针数组,对应矩阵每行一个链表, 只存非 0元素

图示:就是把邻接矩阵表示的每一行抽出来做链表,去掉0元素。

结构体定义:

typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode {Vertex AdjV; /* 邻接点下标 */WeightType Weight; /* 边权重 */PtrToAdjVNode Next;
};
/* AdjVNode是邻接表中结点类型 */typedef struct Vnode{PtrToAdjVNode FirstEdge;DataType Data; /* 存顶点的数据 */
} AdjList[MaxVertexNum];
/* AdjList是邻接表类型 */typedef struct GNode *PtrToGNode;
struct GNode {int Nv; /* 顶点数 */int Ne; /* 边数 */AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph;
/* 以邻接表方式存储的图类型 */

优点:

方便找任一顶点的所有“邻接点”
节约稀疏图的空间需要 N个头指针 + 2E个结点(每个结点至少 2个域)
方便计算任一顶点的“度”?

对无向图:是的

对有向图:只能计算“出度”;需要构造“逆邻接表”(存指向自己 的边)来方便计算“入度”

缺点:

不方便检查任意一对顶点存在边。

 5.图的建立C语言实现

 邻接矩阵式

#include <stdio.h>
#include <stdlib.h>#define MaxVertexNum 100typedef int WeightType;
typedef int DataType;typedef struct GNode {WeightType G[MaxVertexNum][MaxVertexNum];int Nv; /* 顶点数 */int Ne; /* 边数 */DataType Data[MaxVertexNum]; /* 存顶点的数据 */
} *PtrToGNode;typedef PtrToGNode MGraph;typedef int Vertex;
typedef struct {Vertex V1, V2;WeightType Weight;
} Edge;// 创建并返回一个空图
MGraph Create() {MGraph graph = (MGraph)malloc(sizeof(struct GNode));if (graph == NULL) {printf("无法分配内存!\n");exit(1);}graph->Nv = 0;graph->Ne = 0;int i; for (i = 0; i < MaxVertexNum; i++) {int j;for (j = 0; j < MaxVertexNum; j++) {graph->G[i][j] = 0;}}return graph;
}// 将顶点v插入图G
MGraph InsertVertex(MGraph G, Vertex v) {if (G->Nv >= MaxVertexNum) {printf("顶点数已达到最大值!\n");return G;}G->Data[G->Nv] = v;G->Nv++;return G;
}// 将边e插入图G
MGraph InsertEdge(MGraph G, Edge e) {if (e.V1 >= G->Nv || e.V2 >= G->Nv) {printf("边的顶点超出范围!\n");return G;}G->G[e.V1][e.V2] = e.Weight;G->G[e.V2][e.V1] = e.Weight; // 无向图的边,需对称赋值G->Ne++;return G;
}int main() {MGraph G = Create();G = InsertVertex(G, 1);G = InsertVertex(G, 2);G = InsertVertex(G, 3);Edge e1 = {0, 1, 10};Edge e2 = {1, 2, 20};G = InsertEdge(G, e1);G = InsertEdge(G, e2);printf("图的顶点数:%d, 边数:%d\n", G->Nv, G->Ne);int i;for (i = 0; i < G->Nv; i++) {int j;for (j = 0; j < G->Nv; j++) {if (G->G[i][j] != 0) {printf("边(%d, %d) 权重: %d\n", i, j, G->G[i][j]);}}}free(G);return 0;
}

 

 邻接表式

#include <stdio.h>
#include <stdlib.h>#define MaxVertexNum 100typedef int WeightType;
typedef int DataType;
typedef int Vertex;typedef struct AdjVNode {Vertex AdjV;       // 邻接点下标WeightType Weight; // 边权重struct AdjVNode *Next;
} *PtrToAdjVNode;typedef struct Vnode {PtrToAdjVNode FirstEdge;DataType Data; // 存顶点的数据
} AdjList[MaxVertexNum];typedef struct GNode {int Nv; // 顶点数int Ne; // 边数AdjList G; // 邻接表
} *PtrToGNode;typedef PtrToGNode LGraph;typedef struct {Vertex V1, V2; // 边的两个顶点WeightType Weight; // 边的权重
} Edge;// 创建并返回一个空图
LGraph Create() {LGraph graph = (LGraph)malloc(sizeof(struct GNode));if (graph == NULL) {printf("无法分配内存!\n");exit(1);}graph->Nv = 0;graph->Ne = 0;int i;for (i = 0; i < MaxVertexNum; i++) {graph->G[i].FirstEdge = NULL;}return graph;
}// 将顶点v插入图G
LGraph InsertVertex(LGraph G, DataType v) {if (G->Nv >= MaxVertexNum) {printf("顶点数已达到最大值!\n");return G;}G->G[G->Nv].Data = v;G->Nv++;return G;
}// 将边e插入图G
LGraph InsertEdge(LGraph G, Edge e) {if (e.V1 >= G->Nv || e.V2 >= G->Nv) {printf("边的顶点超出范围!\n");return G;}PtrToAdjVNode newNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));if (newNode == NULL) {printf("无法分配内存!\n");exit(1);}newNode->AdjV = e.V2;newNode->Weight = e.Weight;newNode->Next = G->G[e.V1].FirstEdge;G->G[e.V1].FirstEdge = newNode;// 如果是无向图,也需要添加对称的边PtrToAdjVNode newNode2 = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));if (newNode2 == NULL) {printf("无法分配内存!\n");exit(1);}newNode2->AdjV = e.V1;newNode2->Weight = e.Weight;newNode2->Next = G->G[e.V2].FirstEdge;G->G[e.V2].FirstEdge = newNode2;G->Ne++;return G;
}int main() {LGraph G = Create();G = InsertVertex(G, 1);G = InsertVertex(G, 2);G = InsertVertex(G, 3);Edge e1 = {0, 1, 10};Edge e2 = {1, 2, 20};G = InsertEdge(G, e1);G = InsertEdge(G, e2);printf("图的顶点数:%d, 边数:%d\n", G->Nv, G->Ne);int i;for (i = 0; i < G->Nv; i++) {printf("顶点 %d 的邻接点:", i);PtrToAdjVNode node = G->G[i].FirstEdge;while (node != NULL) {printf(" (%d, %d)", node->AdjV, node->Weight);node = node->Next;}printf("\n");}// 释放内存int j;for (j = 0; j < G->Nv; j++) {PtrToAdjVNode node = G->G[j].FirstEdge;while (node != NULL) {PtrToAdjVNode temp = node;node = node->Next;free(temp);}}free(G);return 0;
}

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

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

相关文章

Java的日期类

1.第一代日期类 ① Date类&#xff1a;精确到毫秒&#xff0c;代表特定的瞬间 public static void main(String[] args) { // 获取当前系统时间 // 这里的Date类是在java.util包 // 默认输出的格式是国外的格式Date date new Date();System.out.println…

C#体检系统源码,医院健康体检系统PEIS,C#+VS2016+SQLSERVER

体检中心/医院体检科PEIS系统源码&#xff0c;C#健康体检信息系统源码&#xff0c;PEIS源码 开发环境&#xff1a;C/S架构C#VS2016SQLSERVER 2008 检前&#xff1a; 多种预约方式网站预约、电话预约、微信平台预约及检前沟通&#xff0c;提前制作套餐&#xff0c;客人到达体检…

【原创】java+ssm+mysql医生信息管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 开发背景&#xff1a; 随着信息技术的…

【七】Hadoop3.3.4基于ubuntu24的分布式集群安装

文章目录 1. 下载和准备工作1.1 安装包下载1.2 前提条件 2. 安装过程STEP 1: 解压并配置Hadoop选择环境变量添加位置的原则检查环境变量是否生效 STEP 2: 配置Hadoop2.1. 修改core-site.xml2.2. 修改hdfs-site.xml2.3. 修改mapred-site.xml2.4. 修改yarn-site.xml2.5. 修改hado…

【Linux从青铜到王者】tcp协议2

滑动窗口 滑动窗口是什么 上篇提到如果两端发送数据如果是一发一收那就是串行&#xff0c;效率很低&#xff0c;所以可以一次发送多个报文&#xff0c;一次也可以接受多个报文&#xff0c;可以大大的提高性能(其实是将多个段的等待时间重叠在一起了&#xff09; 那么是怎么发…

解锁人工智能学习中的数学密钥

一、启航&#xff1a;奠定数学基础 1. 线性代数&#xff1a;AI的入门语言 学习目标&#xff1a;掌握向量、矩阵的基本概念及运算&#xff0c;理解线性空间、线性变换及特征值、特征向量的意义。学习建议&#xff1a;从基础教材入手&#xff0c;如《线性代数及其应用》&#x…

【黄啊码】零代码动手创建ModelScope Agent

还没开始学习&#xff0c;先来回复一下&#xff0c;什么是Agent Agent包含的模块 好了&#xff0c;开始发放干货&#xff1a; 1、创建通义千问API (新注册用户有一定的限时免费额度) 2、登录阿里云账号&#xff0c;打开 DashScope管理控制台&#xff0c;开通 DashScope灵积模…

WinUI vs WPF vs WinForms: 三大Windows UI框架对比

1.前言 在Windows平台上开发桌面应用程序时&#xff0c;WinUI、WPF和WinForms是三种主要的用户界面框架。每种框架都有其独特的特点和适用场景。本文将通过示例代码&#xff0c;详细介绍这些框架的优缺点及其适用场景&#xff0c;帮助dotnet桌面开发者更好地选择适合自己项目的…

使用EasyAR打包安卓操作注意

EasyAR for Scene 4.6.3 丨Unity2020.3.15f2 打包Unity注意事项 一、默认渲染管线 官方参考链接&#xff1a;ARFoundation 简单注意 1.打包设置为Android平台 2.PackageName和EasyAR中保持一致 3.Scripting Backend设置为IL2CPP&#xff0c;以及设置为ARM64 4.取消Auto …

数据结构·红黑树

1. 红黑树的概念 红黑树&#xff0c;是一种搜索二叉树&#xff0c;但在每个节点上增加一个存储位表示节点的颜色&#xff0c;可以是Red或Black。通过对任意一条从根到叶子的路径上各个节点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出两倍&#xff0c;因…

秋招突击——7/29——复习{有塔游戏——关联传递性}——新作{随机链表的复制、合并K个升序链表,二叉树——二叉树的中序遍历、二叉树的最大深度、反转二叉树}

文章目录 引言复习有塔游戏——关联传递性实现复习实现参考实现 新作随机链表的复制个人实现参考实现 排序链表个人实现参考实现 二叉树章节二叉树的中序遍历个人实现 二叉树的最大深度个人实现参考实现 反转二叉树个人实现参考实现 总结 引言 旅游完回来了&#xff0c;今天继…

Matlab编程资源库(14)常微分方程初值问题的数值解法

一、 龙格&#xff0d;库塔法简介 龙格-库塔法&#xff08;Runge-Kutta method&#xff09;是一种常用的数值解微分方程的方法&#xff0c;由德国数学家卡尔龙格&#xff08;Carl Runge&#xff09;和马丁威尔海尔姆库塔&#xff08;Martin Wilhelm Kutta&#xff09;在20世纪…

IDEA 本地有jar包依赖文件,但是所有引用的jar包全部爆红

前端时间 看源码&#xff0c;下载源码额按钮不见了&#xff0c;折腾了很久&#xff0c;遂打算重新安装idea&#xff0c;但是重新安装后&#xff0c;发现代码全都爆红&#xff0c;按照晚上说的删除idea 文件夹&#xff0c;idea缓存删除&#xff0c;都不好使&#xff0c;但是看到…

【JavaScript】`Map` 数据结构

文章目录 一、Map 的基本概念二、常见操作三、与对象的对比四、实际应用场景 在现代 JavaScript 中&#xff0c;Map 是一种非常重要且强大的数据结构。与传统的对象&#xff08;Object&#xff09;不同&#xff0c;Map 允许您使用各种类型的值作为键&#xff0c;不限于字符串或…

机器学习算法——常规算法,在同的业务场景也需要使用不同的算法(一)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【Vulnhub系列】Vulnhub_SecureCode1靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_SecureCode1靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境配置 1、从百度网盘下载对应靶机的.ova镜像 2、在VM中选择【打开】该.ova 3、选择存储路径&#xff0…

“数说”巴黎奥运会上的“中国智造”成果

引言&#xff1a;随着“中国智造”在欧洲杯上方兴未艾&#xff0c;在巴黎奥运会上&#xff0c;中国智造继续以多种形式和领域展现了其强大的实力和创新能力。以格力公开表示将为巴黎奥运村提供345台格力空调&#xff0c;为中国制造的清凉送至巴黎事件拉开中国制造闪亮巴黎奥运会…

浅谈取样器之调试取样器

浅谈取样器之调试取样器 JMeter的调试取样器(Debug Sampler)是一个非常实用的工具&#xff0c;它帮助用户在测试计划执行过程中获取详细的内部状态信息&#xff0c;这对于诊断脚本错误、理解变量作用域、以及确认配置是否按预期工作至关重要。调试取样器可以显示JMeter变量、属…

将gitee 上的nvim 配置 从gitee 上下载下来,并配置虚拟机

首先是下载 gitee 上的配置。 然后是 配置 tmux 然后是配置nvim . 1 在init.lua 文件中注释掉所有的与第三方插件有关的内容。 2 在packer 的文件中 &#xff0c; 注释掉所有的与 第三方插件有关的代码。 3 首先要保证 packer 能够正确的安装。 4 然后开始 安装 所有的插件…

【SOC 芯片设计 DFT 学习专栏 -- DFT DRC规则检查】

请阅读【嵌入式及芯片开发学必备专栏】 请阅读【芯片设计 DFT 学习系列 】 如有侵权&#xff0c;请联系删除 转自&#xff1a; 芯爵ChipLord 2024年07月10日 12:00 浙江 文章目录 概述DRC的概念Tessent DRC检查的概述时钟相关检查扫描相关检查BIST规则检查预DFT时钟规则检查 …