第1关:图的邻接矩阵存储及求邻接点操作

2023-11-21 16:36

本文主要是介绍第1关:图的邻接矩阵存储及求邻接点操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 任务要求
  • 参考答案
  • 评论2
  • 任务描述
  • 相关知识
    • 顶点集合
    • 边集合
  • 编程要求
  • 测试说明

任务描述

本关任务:要求从文件输入顶点和边数据,包括顶点信息、边、权值等,编写程序实现以下功能。 1)构造无向网G的邻接矩阵和顶点集,即图的存储结构为邻接矩阵。 2)输出无向网G的各顶点和邻接矩阵。 3)输出无向网G中顶点H的所有邻接顶点。

相关知识

图是表达“多对多”的关系的一种数据结构,由非空的有限顶点集合和有限边集合组成。将图的类型定义为枚举类型,在枚举值表中罗列:

enum GraphKind{DG,DN,UDG,UDN}; // 有向图,有向网,无向图,无向网

顶点集合

每个顶点数据类型为VertexType,一个图的顶点集合用数组表示,数组下标表示顶点位置。数组内容包含顶点的信息,图的顶点集合的数据类型定义如下:

 
  1. #define MAX_VERTEX_NUM 20 // 最大顶点个数
  2. typedef char VertexType[16]; // 顶点类型
  3. VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量

将顶点数据类型定义为长度为16的字符数组类型,可以将表示的城市名称存储在计算机中。

边集合

邻接矩阵是表示顶点之间相邻关系的矩阵。设G=(V,E)是具有n顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵:

图及邻接矩阵

网及邻接矩阵

用邻接矩阵来表示一个具有n个顶点的图时,用邻接矩阵中的n×n个元素存储顶点间相邻关系,对于无权图,当邻接矩阵中的元素仅表示相应的边是否存在时,VRType可定义为值为01的枚举类型,0表示两个顶点之间没有边,即没有关系。对于带权图,则为权值,如果两个顶点之间没有边,则用一个很大很大的数代替。将顶点关系类型VRType定义为整型:

typedef int VRType; // 顶点关系边的数据类型

顶点关系边的数据类型类型,对于无权图,用1或0表示相邻否;对于带权图,则为权值。

图的边集合的数据类型定义如下:

 
  1. #define INFINITY INT_MAX // 用整型最大值代替∞
  2. typedef struct
  3. {
  4. VRType adj;
  5. } ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

说明: AcrCellAdjMatrix都是类型的名称,若有定义: AdjMatrix arcs;arcs是一个以元素类型为AcrCell20*20二维数组。上述声明与下面等同: ArcCell arcs [MAX_VERTEX_NUM][MAX_VERTEX_NUM];

图的邻接矩阵存储表示,类型定义如下:

 
  1. struct MGraph
  2. {
  3. VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
  4. AdjMatrix arcs; // 邻接矩阵
  5. int vexnum, arcnum; // 图的当前顶点数和弧数
  6. GraphKind kind; // 图的种类标志
  7. };

图的邻接矩阵表示法是图的一种顺序存储结构,优点是可以快速判断两个顶点之间是否存在边,可以快速添加边或者删除边,可以快速计算顶点度数、求邻接点的操作等;而其缺点是如果顶点之间的边比较少,会比较浪费空间。

邻接矩阵具有如下性质: (1)图中各项点的序号确定后,图的邻接矩阵是唯一确定的; (2)无向图和无向网的邻接矩阵是一个对称矩阵; (3)无向图邻接矩阵中第i行(或第i列)的非0元素的个数即为第i个顶点的度; (4)有向图邻接矩阵中第i行非0元素的个数为第i个顶点的出度,第i列非0元素的个数为第i个顶点的入度,第i个顶点的度为第i行与第j非0元素个数之和; (5)无向图的边数等于邻接矩阵中非0元素个数之和的一半,有向图的弧数等于邻接矩阵中非0元素个数之和。

编程要求

根据提示,在右侧编辑器补充代码,要求从文件中输入顶点和边数据,包括顶点信息、边、权值等,编写函数实现图的基本运算:

 
  1. void CreateGraphF(MGraph &G);// 采用数组(邻接矩阵)表示法,由文件构造无向网G
  2. void Display(MGraph G); // 输出邻接矩阵存储表示的图G
  3. int LocateVex(MGraph G,VertexType u);//若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
  4. VertexType& GetVex(MGraph G,int v); // v是G中某个顶点的序号,返回v的值
  5. int FirstAdjVex(MGraph G,VertexType v);//v是图G中某个顶点,返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1
  6. int NextAdjVex(MGraph G,VertexType v,VertexType w);//v是G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号,若w是v的最后一个邻接顶点,则返回-1
  7. void DestroyGraph(MGraph &G); // 销毁图G

测试说明

平台会对你编写的代码进行测试:

测试输入: 3 lt.txt 武汉

输入说明: 第一行输入3,表示输入图的类型为无向网。 第二行输入文件名,该文件里保存了图的数据信息,内容如下: 6 9 武汉 上海 长沙 南京 成都 广州 武汉 长沙 9 武汉 成都 2 长沙 上海 2 长沙 南京 2 上海 南京 5 上海 广州 4 上海 成都 3 南京 广州 8 成都 广州 6

第1行为图的顶点的个数n; 第2行为图的边的条数m; 第3行至第n+2行是n个顶点的数据; 第n+3行至第n+m+2行是m条边的数据; 最后输入一个顶点的数据

预期输出: 无向网 6个顶点9条边。顶点依次是: 武汉 上海 长沙 南京 成都 广州 图的邻接矩阵: ∞ ∞ 9 ∞ 2 ∞ ∞ ∞ 2 5 ∞ ∞ 9 2 ∞ 2 ∞ ∞ ∞ 5 2 ∞ ∞ ∞ 2 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ 长沙 成都

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h>
#include<limits.h> typedef int VRType;    // 顶点关系类型 
typedef char VertexType[20]; // 顶点类型 
// 图的数组(邻接矩阵)存储表示 
#define INFINITY INT_MAX // 用整型最大值代替∞ 
#define MAX_VERTEX_NUM 20 // 最大顶点个数 
typedef enum{DG,DN,UDG,UDN}GraphKind; // {有向图,有向网,无向图,无向网} typedef struct
{VRType adj; // 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否;对带权图,则为权值 
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 二维数组 typedef struct      // 图的数组(邻接矩阵)存储 
{VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量 AdjMatrix arcs; // 邻接矩阵 int vexnum,arcnum; // 图的当前顶点数和弧数 GraphKind kind; // 图的种类标志 
}MGraph;  void visit(VertexType i);void CreateGraphF(MGraph &G);// 采用数组(邻接矩阵)表示法,由文件构造无向网G
void Display(MGraph G);    // 输出邻接矩阵存储表示的图G
int LocateVex(MGraph G,VertexType u);//若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 
VertexType* GetVex(MGraph G,int v);    // v是G中某个顶点的序号,返回v的值
int FirstAdjVex(MGraph G,VertexType v);//v是图G中某个顶点,返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 
int NextAdjVex(MGraph G,VertexType v,VertexType w);//v是G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号,若w是v的最后一个邻接顶点,则返回-1 
void DestroyGraph(MGraph &G); // 销毁图G int main()
{MGraph g;VertexType v1,v2;CreateGraphF(g);      // 利用数据文件创建邻接矩阵表示的图	Display(g);           // 输出图  int i,j,k,n;//printf("请输入顶点的值: ");scanf("%s",v1);//printf("输出图G中顶点%s的所有邻接顶点: ",v1);k=FirstAdjVex(g,v1);while(k!=-1){ strcpy(v2, g.vexs[k] );visit(v2);k=NextAdjVex(g,v1,v2);}printf("\n");    return 0;
}void visit(VertexType i)
{printf("%s ",i);
}void CreateGraphF(MGraph &G)
{// 采用数组(邻接矩阵)表示法,由文件构造无向网G/********** Begin **********/int i,j,k,w;char filename[13];VertexType va,vb;FILE * graphlist;scanf("%d",&G.kind);scanf("%s",filename);graphlist=fopen(filename,"r");fscanf(graphlist,"%d",&G.vexnum);fscanf(graphlist,"%d",&G.arcnum);for(i=0;i<G.vexnum;i++)fscanf(graphlist,"%s",G.vexs[i]);for(i=0;i<G.vexnum;++i)for(j=0;j<G.vexnum;++j){if(G.kind%2)G.arcs[i][j].adj=INFINITY;elseG.arcs[i][j].adj=0;}for(k=0;k<G.arcnum;++k){if(G.kind%2)fscanf(graphlist,"%s%s%d",va,vb,&w);elsefscanf(graphlist,"%s%s",va,vb);i=LocateVex(G,va);j=LocateVex(G,vb);if(G.kind==0)G.arcs[i][j].adj=1;else if(G.kind==1)G.arcs[i][j].adj=w;else if(G.kind==2)G.arcs[i][j].adj=G.arcs[j][i].adj=1;elseG.arcs[i][j].adj=G.arcs[j][i].adj=w;}fclose(graphlist);/********** End **********/
}void Display(MGraph G)
{// 输出邻接矩阵存储表示的图G/********** Begin **********/int i,j;switch(G.kind){case DG:printf("有向图\n");break;case DN:printf("有向网\n");break;case UDG:printf("无向图\n");break;case UDN:printf("无向网\n");}printf("%d个顶点%d条边。顶点依次是: ",G.vexnum,G.arcnum);for(i=0;i<G.vexnum;++i)printf("%s ",G.vexs[i]);printf("\n图的邻接矩阵:\n");for(i=0;i<G.vexnum;i++){for(j=0;j<G.vexnum;j++)if(G.kind%2){if(G.arcs[i][j].adj==INFINITY)printf("%s\t","∞");elseprintf("%d\t",G.arcs[i][j].adj);}elseprintf("%d\t",G.arcs[i][j].adj);printf("\n");}/********** End **********/
}int LocateVex(MGraph G,VertexType u)
{//初始条件:图G存在,u和G中顶点有相同特征// 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 /********** Begin **********/int i;for(i=0;i<G.vexnum;++i)if(strcmp(u,G.vexs[i])==0) return i;return -1;  /********** Begin **********/
}VertexType* GetVex(MGraph G,int v)
{ // 初始条件:图G存在,v是G中某个顶点的序号。操作结果:返回v的值/********** Begin **********/if(v>=G.vexnum || v<0)exit(0);return &(G.vexs[v]); /********** End **********/
}int FirstAdjVex(MGraph G,VertexType v)
{// 初始条件:图G存在,v是G中某个顶点 // 操作结果:返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 /********** Begin **********/int i,j,k;if(G.kind%2)j=INFINITY;elsej=0;k=LocateVex(G,v);for(i=0;i<G.vexnum;i++)if(G.arcs[k][i].adj!=j)return i;return -1;/********** End **********/
}int NextAdjVex(MGraph G,VertexType v,VertexType w)
{// 初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点 // 操作结果:返回v的(相对于w的)下一个邻接顶点的序号,若w是v的最后一个邻接顶点,则返回-1 /********** Begin **********/int i,j,k1,k2;if(G.kind%2)j=INFINITY;elsej=0;k1=LocateVex(G,v);k2=LocateVex(G,w);for(i=k2+1;i<G.vexnum;i++)if(G.arcs[k1][i].adj!=j)return i;return -1;/********** End **********/
}void DestroyGraph(MGraph &G)
{ // 初始条件:图G存在。操作结果:销毁图G /********** Begin **********/int i,j,k=0;if(G.kind%2) k=INFINITY; G.vexnum=0; G.arcnum=0; /********** End **********/
}

输出说明: 第一行输出图的类型。 第二行起输出图的顶点和边的数据信息。 最后一行输出输入顶点的所有邻接点。

这篇关于第1关:图的邻接矩阵存储及求邻接点操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/403603

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

Python使用openpyxl读取Excel的操作详解

《Python使用openpyxl读取Excel的操作详解》本文介绍了使用Python的openpyxl库进行Excel文件的创建、读写、数据操作、工作簿与工作表管理,包括创建工作簿、加载工作簿、操作... 目录1 概述1.1 图示1.2 安装第三方库2 工作簿 workbook2.1 创建:Workboo

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

JSONArray在Java中的应用操作实例

《JSONArray在Java中的应用操作实例》JSONArray是org.json库用于处理JSON数组的类,可将Java对象(Map/List)转换为JSON格式,提供增删改查等操作,适用于前后端... 目录1. jsONArray定义与功能1.1 JSONArray概念阐释1.1.1 什么是JSONA

SpringBoot3.X 整合 MinIO 存储原生方案

《SpringBoot3.X整合MinIO存储原生方案》本文详细介绍了SpringBoot3.X整合MinIO的原生方案,从环境搭建到核心功能实现,涵盖了文件上传、下载、删除等常用操作,并补充了... 目录SpringBoot3.X整合MinIO存储原生方案:从环境搭建到实战开发一、前言:为什么选择MinI

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os