【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

这篇具有很好参考价值的文章主要介绍了【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 图相关文章:

1. 图的建立 - 邻接矩阵与邻接表https://blog.csdn.net/m15253053181/article/details/127552328?spm=1001.2014.3001.55012. 图的遍历 - DFS与BFShttps://blog.csdn.net/m15253053181/article/details/127558368?spm=1001.2014.3001.55013. 顶点度的计算https://blog.csdn.net/m15253053181/article/details/127558599?spm=1001.2014.3001.55014. 最小生成树 - Prim与Kruskalhttps://blog.csdn.net/m15253053181/article/details/127589852?spm=1001.2014.3001.55015. 单源最短路径 - Dijkstra与Bellman-Fordhttps://blog.csdn.net/m15253053181/article/details/127630356?spm=1001.2014.3001.55016. 多源最短路径 - Floydhttps://blog.csdn.net/m15253053181/article/details/128039852?spm=1001.2014.3001.55017. 拓扑排序AOV网https://blog.csdn.net/m15253053181/article/details/128042358?spm=1001.2014.3001.5501


目录

图的建立

1 邻接矩阵

1.1 基本概念

1.2 由文件创建邻接矩阵图

2 邻接表

2.1 基本概念

2.2 由文件创建邻接表

3 邻接矩阵与邻接表之间的转换

3.1 邻接矩阵转邻接表

3.2 邻接表转邻接矩阵


图的建立

以图无向图为例进行讲解(有向图原理一致)。

推荐一个图论画图的网站:CS Academy

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言


1 邻接矩阵

1.1 基本概念

以邻接矩阵G[N][N]表示含有N个顶点的无向图(编号为0~N-1),dis<v_i,v_j>表示两顶点间的距离。

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

复杂度分析

- 时间复杂度:O(n^2)

- 空间复杂度:O(n^2)

优点:

① 便于判断任一对顶点是否有边; ​

② 方便找任意顶点的邻接点; ​

③ 方便计算任意顶点的度。

缺点:

① 适合稠密图,对于稀疏图来说比较浪费空间;

② 统计稀疏图中的边数时浪费时间。

1.2 由文件创建邻接矩阵图

(1)图的数据结构

 /* 邻接矩阵存储图 */
 typedef struct MGraph
 {
     int numV;                            // 顶点数
     int numE;                            // 边数
     char nameV[MaxVertexNum];            // 顶点的名字
     int dis[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
 } MG, *MGraph;

(2)由文件创建邻接矩阵图

想要从文件中读取一个图,我们要知道图中共有几个顶点,每个顶点的编号是什么,各个顶点间边的信息。因此规定数据写入格式如下:

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

需要注意的是,对于无向图来说,起点与终点是谁并不重要。并且在生成矩阵时,需要注意为实对称矩阵,不连通顶点之间距离记为-1。

结果示例:

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

代码如下,注释比较清晰,不再赘述:

 /* 由文件创建邻接矩阵图 */
 MGraph createMGraphByFile(FILE *fp)
 {
     assert(fp);
     MGraph graph = (MGraph)malloc(sizeof(struct MGraph));
     int i, j, count;
     char temp[MaxVertexNum];
     char buffer[MaxVertexNum];
     int nums[3]; // 存放内容:起点 终点 距离
     int countOfEdge = 0;
 ​
     // 读入顶点数 - 第一行
     fgets(buffer, MaxVertexNum, fp);
     graph->numV = atoi(buffer);
 ​
     // 读入顶点的名字 - 仅限1个char
     for (i = 0; i < graph->numV; i++)
     {
         fgets(buffer, MaxVertexNum, fp);
         graph->nameV[i] = buffer[0];
     }
 ​
     // 初始化邻接矩阵
     for (i = 0; i < graph->numV; i++)
         for (j = 0; j < graph->numV; j++)
             graph->dis[i][j] = -1;
 ​
     // 读入邻接矩阵
     while (fgets(buffer, MaxVertexNum, fp))
     {
         j = 0;
         for (i = 0; i < 3; i++) // 起点 终点 距离 3个数据
         {
             count = 0;
             while (buffer[j] >= '0' && buffer[j] <= '9')
             {
                 temp[count] = buffer[j];
                 count++;
                 j++;
             }
             temp[count] = '\0';
             nums[i] = atoi(temp);
             j++;
         }
         graph->dis[nums[0]][nums[1]] = nums[2];
         graph->dis[nums[1]][nums[0]] = nums[2];
         countOfEdge++; // 记录边数
     }
 ​
     // 读入边数
     graph->numE = countOfEdge;
     return graph;
 }

2 邻接表

2.1 基本概念

使用指针数组G[N],G[i]代表以第i个顶点为头结点的链表,只存与之邻接的顶点。

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

复杂度分析

- 时间复杂度:O(n+2e)

- 空间复杂度:O(n+2e)

优点:

① 方便找任意顶点的邻接点; ​

② 节约稀疏图的空间。仅需要N个头指针和2E个结点(每个结点至少2个域); ​

③ 方便计算无向图的度与有向图的出度,对于有向图的入度,需构造“逆邻接表”(存指向自己的边)来方便计算。

缺点:

① 难以判断任一对顶点是否有边。

2.2 由文件创建邻接表

(1)图的数据结构

 /* 邻接表存储图 */
 typedef struct LGNode
 {
     int v;               // 邻接点下标
     int dis;             // 与邻接表该行顶点的距离
     struct LGNode *next; // 下一个结点
 } LG, *LGNode;
 ​
 typedef struct AdjList
 {
     int numV;                 // 顶点数
     int numE;                 // 边数
     char nameV[MaxVertexNum]; // 顶点的名字
     LGNode list;              // 表 - 动态数组
 } AdjL, *AdjList;

(2)由文件创建邻接矩阵图

文件信息和邻接矩阵相同。

结果示例:

【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言

代码如下,注释比较清晰,不再赘述:

 /* 由文件创建邻接表 */
 AdjList createAdjListByFile(FILE *fp)
 {
     assert(fp);
     AdjList L = (AdjList)malloc(sizeof(struct AdjList));
     int i, j, count;
     char temp[MaxVertexNum];
     char buffer[MaxVertexNum];
     int nums[3]; // 存放内容:起点 终点 距离
     int countOfEdge = 0;
 ​
     // 读入顶点数
     fgets(buffer, MaxVertexNum, fp);
     L->numV = atoi(buffer);
 ​
     // 读入顶点的名字 - 仅限1个char
     for (i = 0; i < L->numV; i++)
     {
         fgets(buffer, MaxVertexNum, fp);
         L->nameV[i] = buffer[0];
     }
 ​
     // 初始化邻接表
     L->list = (LGNode)malloc(sizeof(struct LGNode) * L->numV);
     for (i = 0; i < L->numV; i++)
     {
         L->list[i].v = i;
         L->list[i].dis = -1;
         L->list[i].next = NULL;
     }
 ​
     // 读入邻接表
     while (fgets(buffer, MaxVertexNum, fp))
     {
         j = 0;
         for (i = 0; i < 3; i++) // 起点 终点 距离 3个数据
         {
             count = 0;
             // 顶点数可能大于1位数
             while (buffer[j] >= '0' && buffer[j] <= '9')
             {
                 temp[count] = buffer[j];
                 count++;
                 j++;
             }
             temp[count] = '\0';
             nums[i] = atoi(temp);
             j++;
         }
         // 头插法,需将边添加到邻接表对应两行中
         LGNode newNode1 = (LGNode)malloc(sizeof(struct LGNode));
         newNode1->next = L->list[nums[0]].next;
         newNode1->v = nums[1];
         newNode1->dis = nums[2];
         L->list[nums[0]].next = newNode1;
 ​
         LGNode newNode2 = (LGNode)malloc(sizeof(struct LGNode));
         newNode2->next = L->list[nums[1]].next;
         newNode2->v = nums[0];
         newNode2->dis = nums[2];
         L->list[nums[1]].next = newNode2;
 ​
         countOfEdge++; // 记录边数
     }
 ​
     // 读入边数
     L->numE = countOfEdge;
     return L;
 }

3 邻接矩阵与邻接表之间的转换

不常用的功能,仅作参考。文章来源地址https://www.toymoban.com/news/detail-463174.html

3.1 邻接矩阵转邻接表

/* 邻接矩阵转邻接表 */
 AdjList MGraphToAdjList(MGraph graph)
 {
     int i, j;
 ​
     // 初始化邻接表
     AdjList L = (AdjList)malloc(sizeof(struct AdjList));
     L->numV = graph->numV;        // 顶点数
     L->numE = graph->numE;        // 边数
     for (i = 0; i < L->numV; i++) // 顶点的名字
         L->nameV[i] = graph->nameV[i];
     L->list = (LGNode)malloc(sizeof(struct LGNode) * L->numV); // 邻接表初始化
     for (i = 0; i < L->numV; i++)
     {
         L->list[i].v = i;
         L->list[i].dis = -1;
         L->list[i].next = NULL;
     }
 ​
     // 构建邻接表
     for (i = 0; i < L->numV; i++)
     {
         for (j = 0; j < L->numV; j++)
         {
             if (graph->dis[i][j] != -1) // 边存在
             {
                 // 头插法
                 LGNode newNode = (LGNode)malloc(sizeof(struct LGNode));
                 newNode->v = j;
                 newNode->dis = graph->dis[i][j];
                 newNode->next = L->list[i].next;
                 L->list[i].next = newNode;
             }
         }
     }
 ​
     return L;
 }

3.2 邻接表转邻接矩阵

 /* 邻接表转邻接矩阵 */
 MGraph AdjListToMGraph(AdjList L)
 {
     int i, j;
 ​
     // 初始化邻接矩阵
     MGraph graph = (MGraph)malloc(sizeof(struct MGraph));
     graph->numV = L->numV;
     graph->numE = L->numE;
     for (i = 0; i < graph->numV; i++) // 顶点的名字
         graph->nameV[i] = L->nameV[i];
     for (i = 0; i < graph->numV; i++) // 邻接矩阵置为-1
         for (j = 0; j < graph->numV; j++)
             graph->dis[i][j] = -1;
 ​
     // 构建邻接矩阵
     LGNode pMove = NULL;
     for (i = 0; i < L->numV; i++)
     {
         pMove = &(L->list[i]);
         while (pMove)
         {
             graph->dis[i][pMove->v] = pMove->dis;
             pMove = pMove->next;
         }
     }
 ​
     return graph;
 }

到了这里,关于【图】(一)图的建立 - 邻接矩阵与邻接表 - C语言的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图的创建(详解邻接矩阵和邻接表)

    首先,我们来看一下涉及的知识点: 图 :图 G=(V,E) 由 顶点 集 V 和 边 集 E 组成。每条边对应一个点对 (v,w),其中 v,w 属于 V 。如果图中的点对是有序的,那么该图就是 有向图 ,反之为 无向图 。 邻接点 :若顶点 v 与 w 之间存在一条边,则认为顶点 v 与 w 邻接。 权 :图中

    2024年02月06日
    浏览(40)
  • 数据结构——图的基本定义以及图的存储结构,邻接矩阵,邻接表

    目录 图的定义和术语 图的存储结构 顺序存储结构—邻接矩阵 链式存储结构 邻接表 邻接多重表 十字链表 图的遍历 图的连通性问题 有向无环图及其应用 最短路径 图的定义:图是一种非线性的复杂的数据结构,图中的数据元素的关系是多对多的关系 ,在图中我们常常把数

    2024年02月04日
    浏览(55)
  • 【数据结构】邻接矩阵和邻接图的遍历

    本篇文章开始学习数据结构的图的相关知识,涉及的基本概念还是很多的。 本文的行文思路: 学习图的基本概念 学习图的存储结构——本文主要介绍邻接矩阵和邻接表 对每种结构进行深度优先遍历和广度优先遍历 话不多说,狠活献上 等等,先别急,正式学习之前先认识几个

    2024年02月04日
    浏览(50)
  • 图的存储 —— 邻接矩阵

    图的结构比较复杂,任何两个节点之间都可能有关系。 图的存储分为顺序存储和链式存储。 顺序存储包括邻接矩阵和边集数组, 链式存储包括邻接表、链式前向星、十字链表和邻接多重表。 图的存储 —— 邻接矩阵 邻接矩阵通常采用一个一维数组存储图中节点的信息,采用

    2024年02月06日
    浏览(38)
  • 无向图的邻接矩阵

    无向图的邻接矩阵的定义、表示法、度 定义 逻辑结构分为两部分:V和E集合,其中,V是顶点,E是边。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻

    2024年02月04日
    浏览(36)
  • 图论01-【无权无向】-图的基本表示-邻接矩阵/邻接表

    https://github.com/Chufeng-Jiang/Graph-Theory/tree/main/src/Chapt01_Adjacency 代码有删减 代码有删减 只需要改动一行 adj = new TreeSet[V]; //构造邻接表, V行,V个LinkedList 代码有删减

    2024年02月07日
    浏览(41)
  • 图的基本操作(邻接矩阵)

    图是比较常用的一种数据结构,我针对期末考试对其进行了大概整理,形成了本文。 整体上是基于文件进行图的建立,有两种文件内容格式,READMODE ==1时,是读入顶点个数,顶点信息以及邻接矩阵,READMODE ==2时,是读入顶点个数,顶点信息,边的个数,边的信息,样例如下:

    2024年02月04日
    浏览(44)
  • 图的邻接矩阵存储及遍历操作

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

    2024年02月06日
    浏览(40)
  • 图的存储--邻接矩阵/边集数组/邻接表/链式邻接表/链式前向星

    使用二维数组w[u][v]存储点u到点v的边的权值。 一般应用在点数不多的稠密图 时间复杂度:O(n 2 ) 空间复杂度:O(n 2 ) 边集数组e[i]存储第i条边的「起点、终点、边权」。在kruskal算法中,将边按边权排序,直接存边。 时间复杂度:O(nm) 空间复杂度:O(m) 出边数组e[u][i]存储u的所

    2024年02月02日
    浏览(36)
  • 图详解第一篇:图的基本概念及其存储结构(邻接矩阵和邻接表)

    这篇文章开始,我们来学习一种高阶数据结构——图 图是由顶点集合及顶点间的关系(边)组成的一种数据结构:G = (V, E)。 其中: 顶点集合V = {x|x属于某个数据对象集}是有穷非空集合; E = {(x,y)|x,y属于V}或者E = {x, y|x,y属于V Path(x, y)}是顶点间关系的有穷集合,也叫做边的集

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包