【数据结构第 6 章 ②】- 用 C 语言实现邻接矩阵

news2024/10/7 15:02:42

目录

一、邻接矩阵表示法

二、AMGraph.h

三、AMGraph.c

四、Test.c


【数据结构第 6 章 ① 】- 图的定义和基本术语-CSDN博客

由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在存储区中的物理位置来表示元素之间的关系,即图没有顺序存储结构,但可以借助二维数组来表示元素之间的关系,即邻接矩阵表示法。另一方面,由于图的任意两个顶点间都可能存在关系,因此,用链式存储表示图是很自然的事,图的链式存储有多种,有邻接表、十字链表和邻接多重表,应根据实际需要的不同,选择不同的存储结构。


一、邻接矩阵表示法

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

例如,图一中的 G1 和 G2 的邻接矩阵如下所示:

若 G 是网,则邻接矩阵可以定义为:

其中 w_{i, j} 表示边上的权值;​\infty 表示计算机允许的,大于所有边上权值的数。例如,下图所示为一个有向网和它的邻接矩阵。


二、AMGraph.h

用邻接矩阵表示法表示图,除了一个用于存储邻接矩阵的二维数组外,还需要用一个一维数组来存储顶点信息

注意:下面是以无向图为例的

#pragma once

#define DEFAULT_CAPACITY 10

typedef char VertexType;  // 假定顶点的数据类型为 char
typedef int EdgeType;  // 假定边的权值的数据类型为 int

typedef struct AMGraph
{
	VertexType* vertices;  // 顶点表(vertices 是 vertex 的复数)
	EdgeType** edges;  // 邻接矩阵
	int vSize;  // 当前图中的顶点数
	int eSize;  // 当前图中的边数
	int capacity;  // 容量
}AMGraph;

// 基本操作
void AMGraphInit(AMGraph* pg);  // 初始化

void ShowAdjMatrix(AMGraph* pg);  // 显示邻接矩阵

int GetVetexPos(AMGraph* pg, VertexType v);  // 获取顶点的位置

void InsertVertex(AMGraph* pg, VertexType v);  // 插入顶点
void InsertEdge(AMGraph* pg, VertexType v1, VertexType v2);  // 插入边

void EraseVertex(AMGraph* pg, VertexType v);  // 删除顶点
void EraseEdge(AMGraph* pg, VertexType v1, VertexType v2);  // 删除边

int GetFirstAdjVexPos(AMGraph* pg, VertexType v);  // 获取 v 的第一个邻接顶点的位置
int GetNextAdjVexPos(AMGraph* pg, VertexType v, VertexType w);
// 获取 v 的(相对于 w 的)下一个邻接顶点的位置

void AMGraphDestroy(AMGraph* pg);  // 销毁


三、AMGraph.c

  1. 初始化

    void AMGraphInit(AMGraph* pg)
    {
    	assert(pg);
    	pg->vSize = pg->eSize = 0;
    	pg->capacity = DEFAULT_CAPACITY;
    
    	pg->vertices = (VertexType*)malloc(sizeof(VertexType) * pg->capacity);
    	assert(pg->vertices);
    
    	pg->edges = (EdgeType**)malloc(sizeof(EdgeType*) * pg->capacity);
    	assert(pg->edges);
    	for (int i = 0; i < pg->capacity; ++i)
    	{
    		pg->edges[i] = (EdgeType*)malloc(sizeof(EdgeType) * pg->capacity);
    		assert(pg->edges[i]);
    		for (int j = 0; j < pg->capacity; ++j)
    		{
    			pg->edges[i][j] = 0;
    		}
    	}
    }
  2. 获取顶点的位置

    int GetVetexPos(AMGraph* pg, VertexType v)
    {
    	assert(pg);
    	for (int i = 0; i < pg->vSize; ++i)
    	{
    		if (pg->vertices[i] == v)
    			return i;
    	}
    	return -1;
    }
  3. 显示邻接矩阵

    void ShowAdjMatrix(AMGraph* pg)
    {
    	assert(pg);
    	printf("  ");  // 输出两个空格
    	for (int i = 0; i < pg->vSize; ++i)
    	{
    		printf("%c ", pg->vertices[i]);
    	}
    	printf("\n");
    
    	for (int i = 0; i < pg->vSize; ++i)
    	{
    		printf("%c ", pg->vertices[i]);
    		for (int j = 0; j < pg->vSize; ++j)
    		{
    			printf("%d ", pg->edges[i][j]);
    		}
    		printf("\n");
    	}
    }
  4. 插入顶点

    void InsertVertex(AMGraph* pg, VertexType v)
    {
    	assert(pg);
    	// 考虑是否需要扩容
    	if (pg->vSize == pg->capacity)
    	{
    		VertexType* tmp1 = (VertexType*)realloc(pg->vertices, sizeof(VertexType) * 2 * pg->capacity);
    		assert(tmp1);
    		pg->vertices = tmp1;
    
    		EdgeType** tmp2 = (EdgeType**)realloc(pg->edges, sizeof(EdgeType*) * 2 * pg->capacity);
    		assert(tmp2);
    		pg->edges = tmp2;
    		for (int i = 0; i < pg->capacity; ++i)
    		{
    			EdgeType* tmp3 = (EdgeType*)realloc(pg->edges[i], sizeof(EdgeType) * 2 * pg->capacity);
    			assert(tmp3);
    			pg->edges[i] = tmp3;
    			for (int j = pg->capacity; j < 2 * pg->capacity; ++j)
    			{
    				pg->edges[i][j] = 0;
    			}
    		}
    		for (int i = pg->capacity; i < 2 * pg->capacity; ++i)
    		{
    			pg->edges[i] = (EdgeType*)malloc(sizeof(EdgeType) * 2 * pg->capacity);
    			assert(pg->edges[i]);
    			for (int j = 0; j < 2 * pg->capacity; ++j)
    			{
    				pg->edges[i][j] = 0;
    			}
    		}
    
    		pg->capacity *= 2;
    	}
    	// 插入顶点
    	pg->vertices[pg->vSize++] = v;
    }
  5. 插入边

    void InsertEdge(AMGraph* pg, VertexType v1, VertexType v2)
    {
    	assert(pg);
    	int pos1 = GetVetexPos(pg, v1);
    	int pos2 = GetVetexPos(pg, v2);
    	if (pos1 == -1 || pos2 == -1)
    		return;
    	
    	if (pg->edges[pos1][pos2] != 0)
    		return;
    
    	pg->edges[pos1][pos2] = pg->edges[pos2][pos1] = 1;
    	++pg->eSize;
    }
  6. 删除顶点

    void EraseVertex(AMGraph* pg, VertexType v)
    {
    	assert(pg);
    	int pos = GetVetexPos(pg, v);
    	if (pos == -1)
    		return;
    
    	// cnt 为和 v 相关联的边的数目
    	int cnt = 0;
    	for (int j = 0; j < pg->vSize; ++j)
    	{
    		if (pg->edges[pos][j] != 0)
    			++cnt;
    	}
    
    	pg->vertices[pos] = pg->vertices[pg->vSize - 1];
    
    	for (int j = 0; j < pg->vSize; ++j)
    	{
    		pg->edges[pos][j] = pg->edges[pg->vSize - 1][j];
    	}
    	for (int i = 0; i < pg->vSize; ++i)
    	{
    		pg->edges[i][pos] = pg->edges[i][pg->vSize - 1];
    	}
    
    	--pg->vSize;
    	pg->eSize -= cnt;
    }
    
  7. 删除边

    void EraseEdge(AMGraph* pg, VertexType v1, VertexType v2)
    {
    	assert(pg);
    	int pos1 = GetVetexPos(pg, v1);
    	int pos2 = GetVetexPos(pg, v2);
    	if (pos1 == -1 || pos2 == -1)
    		return;
    
    	if (pg->edges[pos1][pos2] == 0)
    		return;
    
    	pg->edges[pos1][pos2] = pg->edges[pos2][pos1] = 0;
    	--pg->eSize;
    }
  8. 获取 v 的第一个邻接顶点

    int GetFirstAdjVexPos(AMGraph* pg, VertexType v)
    {
    	assert(pg);
    	int pos = GetVetexPos(pg, v);
    	if (pos == -1)
    		return -1;
    
    	for (int j = 0; j < pg->vSize; ++j)
    	{
    		if (pg->edges[pos][j] != 0)
    			return j;
    	}
    	return -1;
    }
  9. 获取 v 的(相对于 w 的)下一个邻接顶点

    int GetNextAdjVexPos(AMGraph* pg, VertexType v, VertexType w)
    {
    	assert(pg);
    	int pos1 = GetVetexPos(pg, v);
    	int pos2 = GetVetexPos(pg, w);
    	if (pos1 == -1 || pos2 == -1)
    		return -1;
    
    	for (int j = pos2 + 1; j < pg->vSize; ++j)
    	{
    		if (pg->edges[pos1][j] != 0)
    			return j;
    	}
    	return -1;
    }
  10. 销毁

    void AMGraphDestroy(AMGraph* pg)
    {
    	assert(pg);
    	free(pg->vertices);
    	pg->vertices = NULL;
    
    	for (int i = 0; i < pg->capacity; ++i)
    	{
    		free(pg->edges[i]);
    		pg->edges[i] = NULL;
    	}
    	free(pg->edges);
    	pg->edges = NULL;
    
    	pg->vSize = pg->eSize = pg->capacity = 0;
    }


四、Test.c

#include "AMGraph.h"
#include <stdio.h>

int main()
{
	AMGraph g;
	AMGraphInit(&g); 
	InsertVertex(&g, 'A');
	InsertVertex(&g, 'B');
	InsertVertex(&g, 'C');
	InsertVertex(&g, 'D');
	InsertVertex(&g, 'E');
	InsertEdge(&g, 'A', 'B');
	InsertEdge(&g, 'A', 'D');
	InsertEdge(&g, 'B', 'C');
	InsertEdge(&g, 'B', 'E');
	InsertEdge(&g, 'C', 'D');
	InsertEdge(&g, 'C', 'E');
	ShowAdjMatrix(&g);
	printf("\n");

	EraseVertex(&g, 'C');
	ShowAdjMatrix(&g);
	printf("\n");

	EraseEdge(&g, 'A', 'B');
	ShowAdjMatrix(&g);
	printf("\n");

	printf("%d\n", GetFirstAdjVexPos(&g, 'A'));  // 3
	printf("%d\n", GetNextAdjVexPos(&g, 'A', 'D'));  // -1
	AMGraphDestroy(&g);
	return 0;
}

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

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

相关文章

内核上项目【通信】

文章目录 目的操作步骤逆向分析实现代码参考文献 目的 在Win7 64位系统上编写驱动利用ExRegisterAttributeInformationCallback注册回调进行通信 操作步骤 1.利用MmGetSystemRoutineAddress获取ExRegisterAttributeInformationCallback中ExpDisSetAttributeInformation、Exp…

detectron2中save_text_instance_predictions⭐

save_text_instance_predictions demo.py中修改关于路径os.path.join()函数用于路径拼接文件路径&#xff0c;可以传入多个路径os.path.basename(path)就是给定一串路径的最终找到的那个文件python官方文档链接 将 Python 对象序列化为 JSON 字符串with open 打开文件&#xff…

基于.NET Core + Quartz.NET+ Vue + IView开箱即用的定时任务UI

前言 定时任务调度应该是平时业务开发中比较常见的需求&#xff0c;比如说微信文章定时发布、定时更新某一个业务状态、定时删除一些冗余数据等等。今天给大家推荐一个基于.NET Core Quartz.NET Vue IView开箱即用的定时任务UI&#xff08;不依赖数据库,只需在界面做简单配…

java--HashMap、LinkedHashMap、TreeMap底层原理

1.HashMap集合的底层原理 ①HashMap跟HashSet的底层原理是一模一样的&#xff0c;都是基于哈希表实现的。 ②实际上&#xff1a;原来学的Set系列集合的底层原理就是基于Map实现的&#xff0c;只是Set集合中的元素只要键数据&#xff0c;不要值数据而已。 2.哈希表 ①JDK8之前…

如何使用nacos进行配置管理以及代码集成

首先需要在maven的pom文件中引入nacos-config依赖 <!--nacos配置管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency> 在项目中添加boo…

好用便签有什么软件?好用的便签是什么

在工作中&#xff0c;我经常需要记录一些重要的信息&#xff0c;以便在需要时能够快速查找。但是&#xff0c;我曾经使用过的便签软件总是让我感到不满意&#xff0c;要么功能不够强大&#xff0c;要么使用起来不够方便。我一直在寻找一款好用的便签软件&#xff0c;能够让我事…

使用Kali Linux端口扫描

端口扫描 【实训目的】 掌握端口扫描的基本概念和端口扫描的原理&#xff0c;掌握各种类型端口扫描的方法及其区别。 【场景描述】 在虚拟机环境下配置4个虚拟系统“Win XP1” “Win XP2” “Kali Linux”和“Metasploitable2”&#xff0c;使得4个系统之间能够相互通信。实…

软件兼容性测试:保障多样化用户体验的重要功能

随着移动设备和操作系统的快速发展&#xff0c;软件兼容性测试变得越发重要。这项测试确保软件在不同平台、设备和环境下都能够正常运行&#xff0c;提供一致而稳定的用户体验。下面是软件兼容性测试中的一些关键功能&#xff1a; 1. 跨平台兼容性测试 在不同操作系统上运行的软…

【PHP编程实战】手把手教你如何下载文件,实例代码详解!

本文将向大家详细介绍PHP文件下载实例代码&#xff0c;具有一定的参考价值。对于一个网站而言&#xff0c;文件下载功能几乎是必备的。因此&#xff0c;了解如何使用PHP实现文件下载是非常必要的。在接下来的内容中&#xff0c;我们将一起探讨PHP文件下载的实现方法。 无控制类…

串口实验(中断)

需求&#xff1a; 通过中断的方法接受串口工具发送的字符串&#xff0c;并将其发送回串口工具。 硬件接线&#xff1a; 同上 串口配置&#xff1a; 前 4 步同上 5. 打开中断 编程实现&#xff1a; 1、这段代码主要实现了在接收到回车符时判断是否接收到换行符&#xff0c…

正态总体的区间估计

目录 一、区间估计 1.区间估计原理 2.区间估计定义 二、三大分布 1.正态分布 2.χ分布 3.t分布 三、 情况分类 1. μ 的区间估计 (1)已知σ (2)未知σ 2. σ的区间估计 四、公式推导 1.标准正态分布 2.t分布 3. χ分布 五、例题 一、区间估计 1.区间估计原理…

前沿重器[39] | 对话式推荐系统——概念和技术点

前沿重器 栏目主要给大家分享各种大厂、顶会的论文和分享&#xff0c;从中抽取关键精华的部分和大家分享&#xff0c;和大家一起把握前沿技术。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。&#xff08;算起来&#xff0c;专项启动已经…

P1单片机定时器配置及定时器中断——C51(超详细)

目录 1. 简介 1.1 概念解读 1.2 定时器怎么定时 1.什么是晶振 2.什么是时钟周期 3.什么是机器周期 4.加1经过了多少时间 1.3 定时器编程 1.如何算出10ms定时器的初值(TL0 TH0) 2.关于TCON ,怎么知道爆表 3.怎么开始计时(TR0) 4.定时器使用是有很多种模式的&#xf…

sylar高性能服务器-配置(P10-p11)代码解析+调试分析

文章目录 p9&#xff1a;配置模块搭建一、ConfigvarBase二、ConfigVar三、Config四、小结 p10&#xff1a;YAML的使用一、安装yaml-cpp二、使用yaml-cpp三、代码解析 P11&#xff1a;YAML与日志的整合一、方法函数二、代码调试三、test_config结果四、小结 p9&#xff1a;配置模…

2023年全球软件开发大会(QCon广州站2023)-核心PPT资料下载

一、峰会简介 本次峰会包含&#xff1a;泛娱乐时代的边缘计算与通讯、稳定性即生命线、下一代软件架构、出海的思考、现代数据架构、AGI 与 AIGC 落地、大前端技术探索、编程语言实战、DevOps vs 平台工程、新型数据库、AIGC 浪潮下的企业出海、AIGC 浪潮下的效能智能化、数据…

联邦边缘学习中的知识蒸馏综述

联邦边缘学习中的知识蒸馏综述 移动互联网的快速发展伴随着智能终端海量用户数据的产生。如何在保护数据隐私的前提下,利用它们训练出性能优异的机器学习模型,一直是业界关注的难点。为此,联邦学习应运而生,它允许在终端本地训练并协同边缘服务器进行模型聚合来实现分布式机器…

C++字符串插入函数(insert)

1.在下标为n处插入y #include <iostream> #include <algorithm> #include <string> using namespace std;string x,y; int n;int main() {cin>>x>>y>>n;x.insert(n,y); //在下表为n处插入ycout<<x<<endl;return 0; }2…待续

十几个软件测试实战项目【外卖/医药/银行/电商/金融】

项目一&#xff1a;ShopNC商城 项目概况&#xff1a; ShopNC商城是一个电子商务B2C电商平台系统&#xff0c;功能强大&#xff0c;安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城&#xff0c;系统PC后台是基于ThinkPHP MVC构架开发的跨…

【TiDB理论知识10】TiDB6.0新特性

新特性 Placement Rules in SQL 小表缓存 内存悲观锁 Top SQL TiDB Enterprise Manager 一 Placement Rules in SQL Placement Rules in SQL 之前会遇到的问题 比如 北京的业务需要访问 T2 和 T3表 &#xff0c;但是T3表的数据在纽约 纽约的业务需要问访T4 T5 T6表…

基于PaddleNLP的深度学习对文本自动添加标点符号(一)

前言 目前以深度学习对文本自动添加标点符号研究很少&#xff0c;已知的开源项目并不多&#xff0c;详细的介绍就更少了&#xff0c;但对文本自动添加标点符号又在古文识别语音识别上有重大应用。 基于此&#xff0c;本文开始讲解基于PaddleNLP的深度学习对文本自动添加标点符号…