当前位置: 首页 > news >正文

数据结构中无向图的邻接矩阵详解

在计算机科学的浩瀚宇宙中,数据结构无疑是那把开启高效编程大门的关键钥匙。对于计算机专业的大学生们来说,数据结构课程是专业学习路上的一座重要里程碑,而其中的图结构更是充满魅力与挑战,像一幅神秘的画卷等待我们去展开。今天,就让我们结合一段精心优化的 C 语言代码,深入探索图结构中邻接矩阵的奥秘,相信这不仅能让你在课堂学习中游刃有余,更能助你在 CSDN 等技术平台上收获知识与成长。​

一、图结构:数据世界的复杂网络​

图结构是一种比线性表和树更为复杂的数据结构,它用于表示对象之间多对多的关系。在现实生活中,图结构的应用无处不在,比如社交网络中人与人的关系、交通网络中城市与道路的连接、互联网中网页之间的链接等等。图由顶点(Vertex)和边(Edge)组成,顶点代表对象,边则表示对象之间的联系。而邻接矩阵,就是图结构众多存储方式中的一种经典方法。​

二、邻接矩阵:直观高效的存储方式​

邻接矩阵是一种用二维数组来存储图的方式。对于一个具有 ​n个顶点的图,我们可以创建一个 ​n×n的二维数组,数组中的元素 ​arcs[i][j]用于表示顶点 ​i和顶点 ​j之间是否存在边。在无向图中,如果顶点 ​i和顶点 j之间有边相连,那么 ​arcs[i][j]=arcs[j][i]=1;如果没有边相连,则 ​arcs[i][j]=arcs[j][i]=0。这种存储方式简单直观,能够快速判断两个顶点之间是否有边,对于一些需要频繁查询边信息的操作非常高效。​我们来看一段 C 语言代码,它实现了无向图邻接矩阵的创建、输出等功能。

#include <stdio.h>
#include <stdlib.h>#define MAXVEX 16                         /*顶点的最大个数*/
typedef char VexType;                     /*顶点的数据类型*/
typedef int AdjType;                      /*邻接矩阵的数据元素的类型*/// 图的邻接矩阵存储结构
typedef struct {VexType vexs[MAXVEX];                 /*顶点表,存储顶点信息*/AdjType arcs[MAXVEX][MAXVEX];         /*邻接矩阵,存储顶点之间的关系*/int n;                                /*图的当前顶点数*/
} GraphMatrix;// 创建一个无向图的邻接矩阵
GraphMatrix* CreateGraph(void) {int i, j, k, e;GraphMatrix *ga = (GraphMatrix *)malloc(sizeof(GraphMatrix));if (ga == NULL) {fprintf(stderr, "内存分配失败\n");return NULL;}// 输入顶点数量并验证do {printf("请输入顶点的个数(1-%d):", MAXVEX);if (scanf("%d", &(ga->n)) != 1 || ga->n < 1 || ga->n > MAXVEX) {printf("输入错误,请输入1-%d之间的整数\n", MAXVEX);while (getchar() != '\n');    // 清除输入缓冲区ga->n = 0;                    // 重置以继续循环} else {break;}} while (1);while (getchar() != '\n');            // 清除输入缓冲区// 输入顶点信息printf("请顺序地输入各顶点的信息(单个字符):\n");for (i = 0; i < ga->n; i++) {printf("顶点 %d: ", i);ga->vexs[i] = getchar();while (getchar() != '\n');        // 清除多余字符}// 初始化邻接矩阵for (i = 0; i < ga->n; i++)for (j = 0; j < ga->n; j++)ga->arcs[i][j] = 0;// 输入边的数量并验证do {printf("请输入边的个数(0-%d):", ga->n * (ga->n - 1) / 2);if (scanf("%d", &e) != 1 || e < 0 || e > ga->n * (ga->n - 1) / 2) {printf("输入错误,请输入有效的边数\n");while (getchar() != '\n');    // 清除输入缓冲区} else {break;}} while (1);while (getchar() != '\n');            // 清除输入缓冲区// 输入边的信息并验证printf("请输入与边相关联的两个顶点的序号(格式:i,j)\n");for (k = 0; k < e; k++) {do {printf("边 %d: ", k + 1);if (scanf("%d,%d", &i, &j) != 2 || i < 0 || i >= ga->n || j < 0 || j >= ga->n) {printf("输入错误,请输入有效的顶点序号(0-%d)\n", ga->n - 1);while (getchar() != '\n'); // 清除输入缓冲区} else {ga->arcs[i][j] = 1;ga->arcs[j][i] = 1;break;}} while (1);while (getchar() != '\n');        // 清除输入缓冲区}return ga;
}// 图的输出
void PrintGraph(GraphMatrix *ga) {if (ga == NULL) {printf("图为空\n");return;}int i, j;printf("\n顶点表为:\n");for (i = 0; i < ga->n; i++)printf("%4d:%c", i, ga->vexs[i]);printf("\n\n邻接矩阵为:\n");printf("   ");for (i = 0; i < ga->n; i++)printf("%4d", i);printf("\n");for (i = 0; i < ga->n; i++) {printf("%2d:", i);for (j = 0; j < ga->n; j++)printf("%4d", ga->arcs[i][j]);printf("\n");}
}// 释放图占用的内存
void DestroyGraph(GraphMatrix *ga) {if (ga != NULL) {free(ga);}
}int main() {GraphMatrix *ga = CreateGraph();if (ga != NULL) {PrintGraph(ga);DestroyGraph(ga); // 释放内存}return 0;
}

运行:

1. 数据结构定义

#define MAXVEX 16                         /*顶点的最大个数*/
typedef char VexType;                     /*顶点的数据类型*/
typedef int AdjType;                      /*邻接矩阵的数据元素的类型*/// 图的邻接矩阵存储结构
typedef struct {VexType vexs[MAXVEX];                 /*顶点表,存储顶点信息*/AdjType arcs[MAXVEX][MAXVEX];         /*邻接矩阵,存储顶点之间的关系*/int n;                                /*图的当前顶点数*/
} GraphMatrix;

这段代码首先定义了顶点的最大个数 MAXVEX ,以及顶点的数据类型 VexType 和邻接矩阵元素的数据类型 AdjType 。然后通过 typedef struct 定义了 GraphMatrix 结构体,它包含了存储顶点信息的数组 vexs 、存储邻接关系的二维数组 arcs ,以及记录当前顶点数的 n 。这个结构体是整个邻接矩阵存储图结构的核心。 

2. 创建图函数 CreateGraph 

GraphMatrix* CreateGraph(void) {int i, j, k, e;GraphMatrix *ga = (GraphMatrix *)malloc(sizeof(GraphMatrix));if (ga == NULL) {fprintf(stderr, "内存分配失败\n");return NULL;}// 输入顶点数量并验证do {printf("请输入顶点的个数(1-%d):", MAXVEX);if (scanf("%d", &(ga->n)) != 1 || ga->n < 1 || ga->n > MAXVEX) {printf("输入错误,请输入1-%d之间的整数\n", MAXVEX);while (getchar() != '\n');    // 清除输入缓冲区ga->n = 0;                    // 重置以继续循环} else {break;}} while (1);// 省略部分代码...return ga;
}

在 CreateGraph 函数中,首先使用 malloc 函数为图结构体分配内存,并检查内存分配是否成功。接着,通过循环和 scanf 函数获取用户输入的顶点个数,并进行严格的输入验证,确保输入的顶点个数在合理范围内。如果输入错误,会提示用户重新输入,并清除输入缓冲区,避免影响后续输入。之后,按照类似的方式获取顶点信息、初始化邻接矩阵、输入边的个数和边的具体信息,每一步都进行了详细的输入验证,保证程序的健壮性。

3. 输出图函数 PrintGraph

void PrintGraph(GraphMatrix *ga) {if (ga == NULL) {printf("图为空\n");return;}int i, j;printf("\n顶点表为:\n");for (i = 0; i < ga->n; i++)printf("%4d:%c", i, ga->vexs[i]);printf("\n\n邻接矩阵为:\n");printf("   ");for (i = 0; i < ga->n; i++)printf("%4d", i);printf("\n");for (i = 0; i < ga->n; i++) {printf("%2d:", i);for (j = 0; j < ga->n; j++)printf("%4d", ga->arcs[i][j]);printf("\n");}
}

PrintGraph 函数用于输出图的顶点表和邻接矩阵。首先检查图指针是否为空,若为空则提示图为空并返回。然后依次输出顶点表,展示每个顶点的序号和对应的字符信息。接着,以整齐美观的格式输出邻接矩阵,添加行列标题,使矩阵更加清晰易懂,方便我们直观地查看图中顶点之间的连接关系。

4. 内存释放函数 DestroyGraph

// 释放图占用的内存
void DestroyGraph(GraphMatrix *ga) {if (ga != NULL) {free(ga);}
}

在程序使用完图结构后,需要释放动态分配的内存,避免内存泄漏。DestroyGraph 函数就是专门用于释放图结构体所占用的内存空间,只要传入的图指针不为空,就调用 free 函数进行释放,确保程序的内存管理合理有效。​

三、邻接矩阵的优缺点与应用场景​

优点​

直观简单:邻接矩阵的存储方式非常直观,通过二维数组可以清晰地看到顶点之间的连接关系,易于理解和实现。​

查询高效:判断两个顶点之间是否有边,只需要访问对应的数组元素,时间复杂度为 ​O(1),对于频繁查询边的操作非常高效。​

方便处理带权图:如果要表示带权图,只需要将邻接矩阵中的元素值改为边的权值即可,实现起来相对简单。​

缺点​

空间浪费:无论图的边数多少,邻接矩阵都需要一个固定大小的二维数组,对于稀疏图(边数远小于顶点数平方的图),会造成大量的空间浪费。​

更新操作复杂:在插入或删除边时,需要修改邻接矩阵中对应的两个元素,并且对于大规模图,这种更新操作的效率较低。​

应用场景​

由于邻接矩阵的特点,它适用于边数较多的稠密图,或者在需要频繁查询边信息、处理带权图的场景中。例如,在一些交通网络的最短路径算法实现中,如果网络连接较为紧密,使用邻接矩阵存储图结构可以方便地进行距离计算和路径查询。​

四、学习数据结构的意义与成长之路​

学习数据结构中的图结构以及邻接矩阵等存储方式,不仅仅是为了完成课程作业和考试,更重要的是培养我们的逻辑思维和问题解决能力。通过对代码的编写、调试和优化,我们能够深入理解数据在计算机中的组织和处理方式,学会如何选择合适的数据结构来解决实际问题。

相关文章:

  • Tic10024介绍
  • 数据清洗之处理缺失点
  • 蓝凌EKP平台表单控件升级:一行配置引入LayUI新UI体验
  • 74系列数字电路时钟冒险解决
  • v4.0 论文投稿-Latex论文投稿注意事项
  • ShardingSphere-读写分离
  • 2024 CKA模拟系统制作 | Step-By-Step | 10、题目搭建-调度 pod 到指定节点
  • 树莓派安装中文字体和中文输入法
  • 鸿蒙OSUniApp 开发支持图片和视频的多媒体展示组件#三方框架 #Uniapp
  • 基线配置管理:为什么它对网络稳定性至关重要
  • java上机测试错题回顾(2)
  • 鸿蒙OSUniApp 开发的商品筛选器与排序功能#三方框架 #Uniapp
  • 互联网大厂Java求职面试:从Spring到微服务的技术探讨
  • 预约按摩小程序源码介绍
  • 数据泄露频发,Facebook的隐私保护是否到位?
  • 青少年编程与数学 02-020 C#程序设计基础 07课题、控制结构
  • 理解vue-cli中的webpack
  • RabbitMQ搭建集群
  • kafka SASL/PLAIN 认证及 ACL 权限控制
  • Python整合Milvus向量数据库案例实战
  • windows.net做网站/提高销售的10种方法
  • 自己做的网站网页滑动不/脚本外链生成工具
  • 寻花问柳一家只做属于男人的网站/自己怎么搭建网站
  • asp.net网站开发/班级优化大师官网登录
  • 重庆网站怎么设置/拼多多代运营收费标准
  • 线上调研问卷在哪个网站上做/天津网站建设