第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;
    else
        return 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;否则返回ERROR
    int 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;
	else
		return -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 **********/
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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; 本课程将帮助您做好…

docker打包chatpdf(自写)

docker打包上传 docker build -t kitelff/chatpdf:v0.1 .##修改镜像名字 docker tag c2c1a0eb4e08 kitelff/chatpdf:v0.1## push docker push kitelff/chatpdf:v0.1上传文件&#xff0c;测试效果

Rust语言精讲:数据类型全解析

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将深入探讨Rust语言中的数据类型&#xff0c;这是理解和掌握Rust的基础。 Rust语言数据类型概览 Rust是静态类型语言&#xff0c;所有变量类型在编译时确定。Rust的数据类型分为两类&#xff1a;标量类型和复合类型。…

GNSS技术在建筑和城市规划中的关键角色

全球导航卫星系统&#xff08;GNSS&#xff09;技术在当今建筑和城市规划领域扮演着至关重要的角色。这一先进的技术为城市的可持续发展、建筑工程的精准施工以及城市规划的科学决策提供了强大的支持。本文将深入探讨GNSS在建筑和城市规划中的关键角色&#xff0c;并分析其对这…

ML-Net:通过深度学习彻底改变多标签分类

一、说明 多标签分类是一项具有挑战性的机器学习任务&#xff0c;其中输入可以同时属于多个类。传统的多标签分类方法通常依赖于将问题转化为一系列二元分类任务或使用集成方法。然而&#xff0c;深度学习的出现开创了多标签分类的新时代&#xff0c;ML-Net 等模型突破了该领域…

【ARM AMBA AXI 入门 15 -- AXI-Lite 详细介绍】

请阅读【ARM AMBA AXI 总线 文章专栏导读】 文章目录 AXI LiteAXI-Full 介绍AXI Stream 介绍AXI Lite 介绍AXI Full 与 AIX Lite 差异总结AXI Lite AMBA AXI4 规范中包含三种不同的协议接口,分别是: AXI4-FullAXI4-LiteAXI4-Stream 上图中的 AXI FULL 和 AIX-Lite 我们都把…

Vscode GDB 查看内存的值

在VSCode的GDB图形界面中&#xff0c;你可以使用"调试控制台(Debug Console)"来查看malloc返回的地址里的值。以下是具体的步骤&#xff1a; 首先&#xff0c;你需要在你的代码中设置一个断点&#xff0c;这个断点应该在malloc函数调用之后&#xff0c;这样你可以获…

企业降低成本方法有哪些?

企业的经营管理离开不两件事&#xff1a;提升营业额&#xff0c;降低成本。企业的发展壮大&#xff0c;离不开销售&#xff0c;按理说&#xff0c;营业额越高&#xff0c;企业的发展就越大&#xff1b;事实上&#xff0c;除了销售好&#xff0c;营业额高&#xff0c;还需重视一…

共谋发展,共赢未来 | 江西航天红源农业科技总经理孟凡明一行莅临拓世科技集团考察参观

在时刻充满着变化与机遇的商业世界里&#xff0c;农业的颠覆与重构已成为产业新风口&#xff0c;在日新月异的当下&#xff0c;农业与乡村正被开辟成为推动产业结构升级的新战场。 2023年11月20日江西航天红源农业科技有限公司总经理孟凡明一行抵达拓世科技集团南昌总部进行考…

OpenLDAP配置web管理界面PhpLDAPAdmin服务-centos9stream

之前已经发了一篇关于centos9下面配置openldap多主高可用集群的内容&#xff0c;不会配置ldap集群的请参考&#xff1a;服务器集群配置LDAP统一认证高可用集群&#xff08;配置tsl安全链接&#xff09;-centos9stream-openldap2.6.2-CSDN博客 这里跟着前篇文章详细说明如何配置…

Vue3入门(与Vue2进行对比)

1. Vue2 选项式 API vs Vue3 组合式API 特点&#xff1a; 代码量变少分散式维护变成集中式维护 2. Vue3的优势 使用create-vue搭建Vue3项目 1. 认识create-vue create-vue是Vue官方新的脚手架工具&#xff0c;底层切换到了 vite &#xff08;下一代前端工具链&#xff09;&…

哈希表HashTable

散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。 哈希表中关键码就是数组的索引下标&#xff0c;然后通过下标直接访问数组中的元素&#xff0c;复杂度O(1) 哈希表本质…

Virtual DOM

Virtual DOM Virtual DOM 产生的原因 Virtual DOM 产生的原因是因为浏览器中的 DOM 是很庞大复杂的&#xff0c;浏览器的标准就是把 DOM 设计的非常复杂&#xff0c;因此频繁操作 DOM 会有性能问题。 Virtual DOM Virtual DOM 就是用一个原生的 JS 对象去描述一个 DOM 节点…

【广州华锐互动】VR防溺水安全内容体验提高群众防溺水意识

在全球各地&#xff0c;溺水是导致儿童和青少年死亡的主要原因之一。据世界卫生组织的统计&#xff0c;全球每年有超过36万人因溺水而死亡&#xff0c;其中大部分是儿童和青少年。因此&#xff0c;提供有效的防溺水教育和培训至关重要。随着科技的发展&#xff0c;虚拟现实&…

3.DDD基本原理

概述 DDD核心知识体系有: 领域、子域、核心子域、通用子域、支撑子域、限界上下文、实体、值对象、聚合和聚合根、领域事件、领域服务、应用服务和分层架构等&#xff1b; 1.领域和子域 领域的基本概念 领域是从事一种专门活动或事业的范围、部类或部门&#xff1b;领域具…

前端学习--React(1)

一、React简介 React由Meta公司研发&#xff0c;是一个用于 构建Web和原生交互界面的库 优势&#xff1a;组件化开发、不错的性能、丰富生态&#xff08;所有框架中最好&#xff09;、跨平台&#xff08;web、ios、安卓&#xff09; 开发环境搭建 打开相应文件夹 新建终端并…

Google App Campaigns的逻辑及其建议

Google App Campaigns&#xff08;Google应用推广&#xff09;是一种广告服务&#xff0c;旨在帮助应用开发者在Google平台上推广其应用程序。本文小编将讲讲Google App Campaigns的逻辑&#xff0c;并提供一些建议&#xff0c;以帮助应用开发者最大程度地利用这项服务。 1、Go…

Java引用类型String源码解析

目录 String解析 final的作用 String是否有长度限制 StringBuffer解析 StringBuilder解析 关键字、操作类相关 引用数据类型非常多大致包括&#xff1a;类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型。String类型就是引用类型。 String解析 JVM运行时会分…

SpringCloud原理-OpenFeign篇(一、Hello OpenFeign项目示例)

文章目录 前言正文一、项目结构二、服务调用链路说明三、Rpc调用链路说明四、项目代码4.1 client 模块中的feign接口4.2 client 中的rest接口4.3 client 中的启动类4.4 server中的rest接口4.5 server中的配置文件 五、调试 前言 本篇是SpringCloud原理系列的 OpenFeign 模块的…

SpringBoot:ch02 配置文件(日志)

前言 简单介绍 Spring Boot 中常见的配置文件类型&#xff0c;如 application.properties 和 application.yml 等&#xff0c;并说明它们各自的特点和用途。 一、前期准备 1、新建项目&#xff0c;结构如下 2、添加依赖 <?xml version"1.0" encoding"UTF…