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

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

任务描述

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

相关知识

对于图来说,邻接矩阵是不错的一种图存储结构,但是对于边数相对顶点较少的图,这种结构对存储空间浪费极大。

因此考虑另外一种存储结构方式:邻接表,即数组与链表相结合的存储结构。

在图的邻接表结构中,用一个连续存储区域来存储图中各顶点的数据,并对图中每个顶点vi建立一个单链表(称为vi的邻接表),把顶点vi的所有相邻顶点(即后继结点)的序号链接起来。

i个单链表中的每一个结点(也称为表结点)均含有三个域:邻接点域、链域和数据域,邻接点域用来存放与顶点vi相邻接的一个顶点的序号,链域用来指向下一个表结点,数据域info存储边的信息(如果边上没有权值,可以省略该info数据域)

另外每个顶点vi设置了表头结点,除了存储本身数据的数据域data外,还设置了一个链域firstarc,作为邻接表的表头指针,指向第一个表结点。n个顶点用一个一维数组表示。如图所示。

邻接表的表结点和头结点示意图

表结点的类型定义如下:

 
  1. typedef struct
  2. {
  3. int adjvex; // 该弧所指向的顶点的位置
  4. int info; // 网的权值
  5. ArcNode *nextarc; // 指向下一条弧的指针
  6. }ArcNode;

头结点的类型定义如下:

 
  1. typedef struct
  2. {
  3. VertexType data; // 顶点信息
  4. ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针
  5. }VNode,AdjList[MAX_VERTEX_NUM];

无向图的邻接表

有向图的邻接表

有向网的邻接表

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

 
  1. typedef struct
  2. {
  3. AdjList vertices;
  4. int vexnum,arcnum; // 图的当前顶点数和弧数
  5. GraphKind kind; // 图的种类标志
  6. }ALGraph;

邻接表具有如下性质:

  1. 图的邻接表表示不是唯一的,它与表结点的链入次序有关,取决于建立邻接表的算法以及边的输入次序;
  2. 无向图的邻接表中第i个边表的结点个数即为第i个顶点的度;
  3. 有向图的邻接表中第i个出边表的结点个数即为第i个顶点的出度,有向图的逆邻接表中第i个入边表的结点个数即为第i个顶点的入度;
  4. 无向图的边数等于邻接表中边表结点数的一半,有向图的弧数等于邻接表的出边表结点的数目,也等于逆邻接表的入边表结点的数目。

编程要求

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

  • void CreateGraphF(ALGraph &G); // 采用邻接表存储结构,由文件构造没有相关信息图或网G

  • void Display(ALGraph G); // 输出图的邻接表G

  • int LocateVex(ALGraph G,VertexType u); //若G中存在顶点u,则返回该顶点在图中位置;否则返回-1

  • int FirstAdjVex(ALGraph G,VertexType v); // 返回v的第一个邻接顶点的序号;否则返回-1

  • int NextAdjVex(ALGraph G,VertexType v,VertexType w);//v是图G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号

测试说明

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

测试输入: 3 lt.txt 徐州

输入说明: 第一行输入3,表示输入图的类型为无向网。 第二行输入文件名,该文件里保存了图的数据信息,内容如下:

图的数据文件

第1行为图的顶点的个数n; 第2行为图的边的条数m; 第3行至第n+2行是n个顶点的数据; 第n+3行至第n+m+2行是m条边的数据; 第三行为一个顶点徐州的数据

预期输出: 无向网 8个顶点: 北京 天津 郑州 徐州 武汉 上海 株洲 南昌 9条弧(边): 北京→郑州 :695 北京→天津 :137 天津→徐州 :674 天津→北京 :137 郑州→武汉 :534 郑州→徐州 :349 郑州→北京 :695 徐州→上海 :651 徐州→郑州 :349 徐州→天津 :674 武汉→株洲 :409 武汉→郑州 :534 上海→徐州 :651 上海→南昌 :825 株洲→南昌 :367 株洲→武汉 :409 南昌→上海 :825 南昌→株洲 :367 上海 郑州 天津

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h>
#include<limits.h> 
typedef char VertexType[20]; // 顶点类型为字符串 
#define MAX_VERTEX_NUM  20
typedef enum{DG,DN,UDG,UDN}GraphKind; // {有向图,有向网,无向图,无向网} 
typedef struct 
{int adjvex; // 该弧所指向的顶点的位置 int info; // 网的权值指针 
}ElemType;
typedef struct ArcNode 
{ElemType data;          // 除指针以外的部分都属于ElemType struct ArcNode *nextarc;   // 指向下一条弧的指针 
}ArcNode;                // 表结点 
typedef struct
{VertexType data;         // 顶点信息 ArcNode *firstarc;       // 第一个表结点的地址,指向第一条依附该顶点的弧的指针 
}VNode,AdjList[MAX_VERTEX_NUM];  // 头结点 
typedef struct
{AdjList vertices;int vexnum,arcnum;       // 图的当前顶点数和弧数 GraphKind kind;          // 图的种类标志 
}ALGraph;#define LNode ArcNode         // 定义单链表的结点类型是图的表结点的类型 
#define next nextarc         // 定义单链表结点的指针域是表结点指向下一条弧的指针域 
typedef ArcNode *LinkList;     // 定义指向单链表结点的指针是指向图的表结点的指针 
int LocateElem(LinkList L,ElemType e,int (*equal)(ElemType,ElemType));
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p);
int ListInsert(LinkList &L,int i,ElemType e);// 在不带头结点的单链线性表L中第i个位置之前插入元素e int equal(ElemType a,ElemType b);
void visit(VertexType i);
void CreateGraphF(ALGraph &G);         // 采用邻接表存储结构,由文件构造没有相关信息图或网G
void Display(ALGraph G);             // 输出图的邻接表G 
int LocateVex(ALGraph G,VertexType u);    //若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
int FirstAdjVex(ALGraph G,VertexType v);  // 返回v的第一个邻接顶点的序号;否则返回-1 
int NextAdjVex(ALGraph G,VertexType v,VertexType w);//v是图G中某个顶点,w是v的邻接顶点,返回v的(相对于w的)下一个邻接顶点的序号int main()
{ALGraph g;VertexType v1,v2;int k;CreateGraphF(g);       // 利用数据文件创建图Display(g);           // 输出图  //printf("请输入顶点的值: ");scanf("%s",v1);//printf("输出图G中顶点%s的所有邻接顶点: ",v1);k=FirstAdjVex(g,v1);while(k!=-1){  strcpy(v2,g.vertices[k].data);visit(v2);k=NextAdjVex(g,v1,v2);}printf("\n");return 0;
}
int equal(ElemType a,ElemType b)
{   if(a.adjvex==b.adjvex)return 1;elsereturn 0;
}
void visit(VertexType i)
{printf("%s ",i);
}int LocateElem(LinkList L,ElemType e,int (*equal)(ElemType,ElemType))
{   // 初始条件: 不带头结点的单链表L已存在,equal()是数据元素判定函数(满足为1,否则为0) // 操作结果: 返回L中第1个与e满足关系equal()的数据元素的位序。 //           若这样的数据元素不存在,则返回值为0 int i=0;LinkList p=L;  // L是不带头结点的单链表while(p){i++;if(equal(p->data,e)) // 找到这样的数据元素 return i;p=p->next;}return 0;
}
LinkList Point(LinkList L,ElemType e,int(*equal)(ElemType,ElemType),LinkList &p)
{  //查找表L中满足条件的结点。如找到,返回指向该结点的指针,p指向该结点的前驱(若该结点是首元结点,则p=NULL)。//如表L中无满足条件的结点,则返回NULL,p无定义。函数equal()的两形参的关键字相等,返回OK;否则返回ERRORint i,j;i=LocateElem(L,e,equal);if(i)                  // 找到 {if(i==1)          // 是首元结点 {p=NULL;return L;}p=L;for(j=2;j<i;j++)p=p->next;return p->next;}return NULL;           // 没找到 
}
int  ListInsert(LinkList &L,int i,ElemType e)
{   // 在不带头结点的单链线性表L中第i个位置之前插入元素e int j=1;LinkList p=L,s;if(i<1) // i值不合法 return 0;s=(LinkList)malloc(sizeof(struct LNode)); // 生成新结点 s->data=e;                         // 给s的data域赋值 if(i==1)                           // 插在表头 {s->next=L;L=s;                           // 改变L }else{ // 插在表的其余处 while(p&&j<i-1)                // 寻找第i-1个结点 {p=p->next;j++;}if(!p)                         // i大于表长+1 return 0;s->next=p->next;p->next=s;}return 1;    
}void CreateGraphF(ALGraph &G)
{   // 采用邻接表 存储结构,由文件构造没有相关信息图或网G(用一个函数构造4种图) /********** Begin **********/int i,j,k,w;            VertexType va,vb;      ElemType e;char filename[13];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.vertices[i].data);G.vertices[i].firstarc=NULL;  }for(k=0;k<G.arcnum;++k)           {if(G.kind%2)                 fscanf(graphlist,"%s%s%d",va,vb,&w);else                         fscanf(graphlist,"%s%s",va,vb);i=LocateVex(G,va);          j=LocateVex(G,vb);          e.info=0;                   e.adjvex=j;                  if(G.kind%2)               {e.info = w;}ListInsert(G.vertices[i].firstarc,1,e); if(G.kind>=2)  {e.adjvex=i;                  ListInsert(G.vertices[j].firstarc,1,e);  }}fclose(graphlist);           /********** End **********/
} 
void Display(ALGraph G)
{   // 输出图的邻接表G /********** Begin **********/int i;LinkList p;switch(G.kind){case DG: printf("有向图\n");break;case DN: printf("有向网\n");break;case UDG:printf("无向图\n");break;case UDN:printf("无向网\n");}printf("%d个顶点:\n",G.vexnum);for(i=0;i<G.vexnum;++i)printf("%s ",G.vertices[i].data);printf("\n%d条弧(边):\n",G.arcnum);for(i=0;i<G.vexnum;i++){p=G.vertices[i].firstarc;while(p){printf("%s→%s ",G.vertices[i].data,G.vertices[p->data.adjvex].data);if(G.kind%2)            printf(":%d\t",p->data.info );			p=p->nextarc;}printf("\n");}/********** End **********/
} 
int LocateVex(ALGraph G,VertexType u)
{   // 初始条件:图G存在,u和G中顶点有相同特征 // 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 /********** Begin **********/int i;for(i=0;i<G.vexnum;++i)if(strcmp(u,G.vertices[i].data)==0) return i;return -1;/********** End **********/
}
int FirstAdjVex(ALGraph G,VertexType v)
{   // 初始条件:图G存在,v是G中某个顶点 // 操作结果:返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 /********** Begin **********/LinkList p;int v1;v1=LocateVex(G,v); p=G.vertices[v1].firstarc;if(p)return p->data.adjvex;elsereturn -1;/********** End **********/
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{   // 初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点 // 操作结果:返回v的(相对于w的)下一个邻接顶点的序号。若w是v的最后一个邻接点,则返回-1 /********** Begin **********/LinkList p,p1; ElemType e;int v1;v1=LocateVex(G,v);        e.adjvex=LocateVex(G,w); p=Point(G.vertices[v1].firstarc,e,equal,p1);  if(!p||!p->next)          return -1;else                       return p->next->data.adjvex;/********** End **********/
}

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

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

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

相关文章

SpringCloud原理-OpenFeign篇(二、OpenFeign包扫描和FeignClient的注册原理)

文章目录 前言正文一、从启动类开始二、EnableFeignClients 的源码分析三、Import FeignClientsRegistrar 的作用四、FeignClientsRegistrar#registerFeignClients(...)五、饥饿注册&懒注册 FeignClientsRegistrar#registerFeignClient(...)六、通过Holder真正注册beanDefi…

SSM框架(一):Spring 容器

文章目录 一、Spring Framework系统框架二、IoC控制反转 与 DI依赖注入 简单入门三、Bean3.1 Bean的配置3.2 实例化Bean的四种方式3.3 Bean的生命周期 四、依赖注入4.1 setter注入4.2 构造器注入4.3 注入方式选择4.4 依赖自动装配4.5 集合注入4.6 案例&#xff1a;配置数据库4.…

「编程学习书籍总结」提升个人能力从读书开始

✍️作者简介&#xff1a;码农小北&#xff08;专注于Java、Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a; 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f449;关注✨、…

CHINTERGEO2023中国测绘地理信息技术装备展览会,大势智慧在3010展台期待您的莅临!

11月27日-11月29日 CHINTERGEO2023中国测绘地理信息技术装备展览会 二层-HALL3展厅-3010 大势智慧携符合信创要求的实景三维软硬件全流程解决方案 为您带来一场全国产、真安全的实景三维新型智能测绘装备盛宴 期待您的莅临&#xff01;

C#使用MaxMind.GeoIP2数据库查询当前ip地址

GeoLite2-City.mmdb下载 因为比较简单&#xff0c;直接上代码&#xff0c;代码展示获取ip地址的国家和城市信息 using MaxMind.GeoIP2; using MaxMind.GeoIP2.Model; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Sy…

超级会员卡积分收银系统源码+会员卡+积分商城+多门店系统 附带完整的搭建教程

时代在发展&#xff0c;商家对于会员管理、积分管理、收银管理以及多门店管理的需求日益增长。为了满足这些需求&#xff0c;开发一款功能全面、易于使用和管理的超级会员卡积分收银系统变得至关重要。 以下是部分代码示例&#xff1a; 系统特色功能一览&#xff1a; 1.会员管…

STM32 -Bin/Hex文件格式解析

文章目录 1. 概述2. Hex文件2.1 格式解析2.2 数据类型2.3 举例解析2.4 合并两个Hex文件方法 3. Bin文件3.1 生成方式3.2 合并多个Bin文件方法3.3 打开Bin文件方式3.4 和Hex文件比较 4 总结 1. 概述 Hex文件&#xff1a;它是单片机和嵌入式工程编译输出的一种常见的目标文件格式…

https想访问本地部署的http://localhost接口

情况说明&#xff1a; 网址是https的&#xff0c;想访问java本地启的一个程序接口http://localhost:8089 解决办法 java程序加上

智能高效的转运机器人,为物流行业注入新动力

在当今社会&#xff0c;随着科技的不断发展&#xff0c;机器人已经逐渐融入到我们的生活中。其中&#xff0c;转运机器人作为物流行业的新秀&#xff0c;正以其高效、智能的特点&#xff0c;引起了广泛的关注。 转运机器人&#xff0c;是指能够自主进行物品搬运和运输的机器人…

如何利用CHATGPT写主题文章

问CHAT&#xff1a;新课标下畅言智慧课堂助力小学生量感培养&#xff0c;拟解决的关键问题 CHAT回复&#xff1a; 1. 确定智慧课堂在新课标下的正确应用方法&#xff1a;新课标对教育方法、内容等提出了新的要求&#xff0c;需要探讨如何将智慧课堂与新课标相结合&#xff0c;…

python-opencv 培训课程笔记(2)

python-opencv 培训课程笔记&#xff08;2&#xff09; 1.图像格式转换 先看一下cvtColor函数的例子 #默认加载彩图 pathrD:\learn\photo\cv\cat.jpg# imread(path,way) #way0 灰度图。way1 彩图 #默认彩图 imgcv2.imread(path) img_dogcv2.imread(path_dog) #图片格式的转化…

django restful framework序列化与反序列化

在前后端分离开发中&#xff0c;对于RESTfulAPI设置&#xff0c;一般需要将查询/更新数据以JSON方式进行返回。 序列化 Model.py from django.db import models class User(models.Model):username models.CharField(verbose_name用户名,max_length10)age models.IntegerF…

Cmake 生成器表达式

CMake生成器表达式 - 招财猫的博客 【精选】CMake I 生成器表达式_cmake生成器表达式-CSDN博客 例子 下面这行 就能把Lib的PDB FILEs安装提取出来安装到DESTINATION

VCP-DCV VMware vSphere,即将开课~想了解点击查看

VCP-DCV VMware vSphere 本周开课~ 想报名的必须提前预约啦 &#x1f447;&#x1f447;&#x1f447; 课程介绍 本课程重点讲授如何安装、配置和管理VMware vSphere 8.0&#xff08;包括VMware ESXi™ 8.0和VMware vCenter Server™ 8.0&#xff09; 本课程将帮助您做好…

火电安全事故vr模拟仿真培训强交互更真实

VR消防&#xff0c;利用VR虚拟现实技术&#xff0c;将VR和消防教育融合在一起达到寓教于乐的效果&#xff0c; VR消防教育是对于家中、校园内、大型商场、公司办公室等情景产品研发的消防安全培训类VR系统软件&#xff0c;根据互动体验、互动、视角实际操作、视听觉系统多度自然…

ubuntu18.04安装并运行ORB-SLAM2

查看版本号 lsb_release -a 换源 Ubuntu系统自带的源都是国外的网址&#xff0c;国内用户在使用的时候下载比较慢甚至无法获取&#xff0c;需要替换成国内的镜像源 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.old 打开文件 sudo gedit /etc/apt/so…

与数字伙伴共赏书海风光,拓世法宝AI智能数字人一体机打造现代图书馆新景象

纪录片《但是还有书籍》中这样形容图书馆“图书馆一个城市最安静的角落&#xff0c;却涌动着最活跃的思想。它保存着文明的火种&#xff0c;也滋养着未来的新知。它是一些人休憩心灵的桃花源&#xff0c;另一些人逃离世界的窗口。它是迷宫&#xff0c;是港口&#xff0c;也是乐…

2022最新版-李宏毅机器学习深度学习课程-P51 BERT的各种变体

之前讲的是如何进行fine-tune&#xff0c;现在讲解如何进行pre-train&#xff0c;如何得到一个pre train好的模型。 CoVe 其实最早的跟预训练有关的模型&#xff0c;应该是CoVe&#xff0c;是一个基于翻译任务的一个模型&#xff0c;其用encoder的模块做预训练。 但是CoVe需要…

OceanBase:集群常见操作

目录 1.查看 OBD 管理的集群列表 2.查看某个集群状态 3.启动 OceanBase 集群 4.连接 OceanBase 集群 5.停止运行中的集群 6.销毁已部署的集群 7.查看集群配置项 8.修改集群配置项 1.查看 OBD 管理的集群列表 obd cluster list 2.查看某个集群状态 obd cluster displa…

CMakeLists.txt基础指令与cmake-gui生成VS项目的步骤

简介 本博客主要介绍cmake的基本指令&#xff0c;同时&#xff0c;很多使用Visual Studio小白从Gitbub下载项目源码后&#xff0c;看到CMakeLists.txt&#xff0c;不知道如何使用Visual Studio编译源码&#xff1b;针对以上问题&#xff0c;做一下简单操作与解释&#xff0c;方…