图的存储结构(邻接矩阵和邻接表)

前言:

前面我们学习图的有些定义和术语,对图这个数据结构有了新的见解和认知,让我们理解图结构的知识,今天我们学习图的存储结构,图的存储结构比较多,我们今天主要是学习邻接矩阵和邻接表,对于邻接矩阵是使用数组的形式,我们不叫顺序存储结构了,叫邻接矩阵,邻接表和我们十字链有异曲同工之处,只不过邻接表的链表要多一点,好了话不多说我们开始学习吧!!!

每日一遍,防止颓废

1.邻接矩阵

官方术语:

邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中V={v1,v2,…,vn} [1]  。G的邻接矩阵是一个具有下列性质的n阶方阵:
①对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为0,有向图则不一定如此。
②在无向图中,任一顶点i的度为第i列(或第i行)所有非零元素的个数,在有向图中顶点i的出度为第i行所有非零元素的个数,而入度为第i列所有非零元素的个数。
③用邻接矩阵法表示图共需要n^2个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n(n-1)/2个空间。

讲人话就是:邻接矩阵和矩阵的三元组表示法有点相似,就是一个顶点,和一个二维数组组合,二维数组的第一个下标表示边的起点,第二下标表示边的终点,有边把这个位置的值赋值为1,没有就赋值为0如下图:.

1.1图的邻接矩阵类型声明:

#include <stdio.h>
#include <malloc.h>
#define MAXVEX 100           //图中最大顶点个数
#define INF 32767               //表示∞
typedef char VertexType[10];        //定义VertexType为字符串类型
typedef struct vertex
{  int adjvex; //顶点编号VertexType data;       //顶点的信息
} VType;        //顶点类型
typedef struct graph
{  int n,e;         //n为实际顶点数,e为实际边数VType vexs[MAXVEX];     //顶点集合int edges[MAXVEX][MAXVEX];        //边的集合
}  MatGraph;        //图的邻接矩阵类型

1.2 建立图的邻接矩阵运算算法

由邻接矩阵数组A、顶点数n和边数e建立图G的邻接矩阵存储结构。

void CreateGraph(MatGraph &g,int A[][MAXVEX],int n,int e)
{  int i,j;g.n=n; g.e=e;for (i=0;i<n;i++)for (j=0;j<n;j++)g.edges[i][j]=A[i][j];
}

1.3销毁图运算算法

这里邻接矩阵是图的一种顺序存储结构,其内存空间是由系统自动分配的,在不再需要时由系统自动释放其空间。所以对应的函数不含任何语句。

void DestroyGraph(MatGraph g)//内存空间是由系统自动分配的,直接关闭程序就释放了
{  }

1.4 输出图运算算法

将图G的邻接矩阵存储结构输出到屏幕上

void DispGraph(MatGraph g)
{  int i,j;for (i=0;i<g.n;i++){  for (j=0;j<g.n;j++)if (g.edges[i][j]<INF)printf("%4d",g.edges[i][j]);elseprintf("%4s","∞");printf("\n");}
}

1.5求顶点度运算算法

对于无向图和有向图,求顶点度有所不同。依据定义,求无向图G中顶点v的度的算法如下:

int Degree1(MatGraph g,int v)     //求无向图中顶点的度
{  int i,d=0;if (v<0 || v>=g.n)return -1;        //顶点编号错误返回-1for (i=0;i<g.n;i++)if (g.edges[v][i]>0 && g.edges[v][i]<INF)d++;     //统计第v行既不为0也不为∞的边数即度return d;
}int Degree2(MatGraph g,int v)   //求有向图中顶点的度
{  int i,d1=0,d2=0,d;if (v<0 || v>=g.n)return -1;  //顶点编号错误返回-1for (i=0;i<g.n;i++)if (g.edges[v][i]>0 && g.edges[v][i]<INF)d1++;     //统计第v行既不为0也不为∞的边数即出度for (i=0;i<g.n;i++)if (g.edges[i][v]>0 && g.edges[i][v]<INF)d2++;        //统计第v列既不为0也不为∞的边数即入度d=d1+d2;return d;
}

1.6 主函数及效果展示

int main(int argc, char** argv)
{MatGraph g;int n=5,e=7,i;int A[MAXVEX][MAXVEX]={{0,1,2,6,INF},{INF,0,INF,4,5},{INF,INF,0,INF,3},{INF,INF,INF,0,INF},{INF,INF,INF,7,0}};CreateGraph(g,A,n,e);    //建立图7.4图的邻接矩阵printf("图G的存储结构:\n"); DispGraph(g);printf("图G中所有顶点的度:\n"); printf("  顶点\t度\n");for (i=0;i<g.n;i++)printf("   %d\t%d\n",i,Degree2(g,i));DestroyGraph(g);return 0;
}

2.邻接表

邻接表是图的一种链式存储结构。在邻接表中,对图中每个顶点建立一个带头结点的单链表,把该顶点的所有相邻点串起来。所有的头结点构成一个数组,称为头结点数组,用adjlist表示,第i个单链表adjlist[i]中的结点表示依附于顶点i的边,也就是说头结点数组元素的下标与顶点编号一致。

讲人话:就是有一个数组类型的单链表,这个数组的每个结点都代表一个头指针,这个头指针再指向一个单链表,这个单链表用来保存下一个你要指向的顶点(也就是头指针)和权值,对权值不知道的同学看博主上一篇文章

2.1图的邻接表存储结构的类型声明如下:

#include <stdio.h>
#include <malloc.h>
#define MAXVEX 100              //图中最大顶点个数
#define INF 32767               //表示∞
typedef char VertexType[10];      //VertexType为字符串类型
typedef struct edgenode
{  int adjvex;            //相邻点序号int weight;              //边的权值struct edgenode *nextarc;     //下一条边的顶点
} ArcNode;      //每个顶点建立的单链表中边结点的类型
typedef struct vexnode
{  VertexType data;       //存放一个顶点的信息ArcNode *firstarc;       //指向第一条边结点
} VHeadNode;              //单链表的头结点类型
typedef struct
{  int n,e;           //n为实际顶点数,e为实际边数VHeadNode adjlist[MAXVEX];      //单链表头结点数组
} AdjGraph;           //图的邻接表类型

2.2 邻接表的创建

void CreateGraph(AdjGraph *&G,int A[][MAXVEX],int n,int e)
{  int i,j;ArcNode *p;G=(AdjGraph *)malloc(sizeof(AdjGraph));G->n=n; G->e=e;for (i=0;i<G->n;i++)  //邻接表中所有头结点的指针域置空G->adjlist[i].firstarc=NULL;for (i=0;i<G->n;i++)  //检查A中每个元素for (j=G->n-1;j>=0;j--)if (A[i][j]>0 && A[i][j]<INF)          //存在一条边{  p=(ArcNode *)malloc(sizeof(ArcNode));  //创建结点pp->adjvex=j;p->weight=A[i][j];p->nextarc=G->adjlist[i].firstarc;  //头插法插入pG->adjlist[i].firstarc=p;}
}

2.3销毁图运算算法

邻接表的头结点和边结点都是采用malloc函数分配的,在不再需要时应用free函数释放所有分配的空间。
基本思路:通过adjlist数组遍历每个单链表,释放所有的边结点,最后释放adjlist数组的空间。

void DestroyGraph(AdjGraph *&G)  //销毁图
{  int i;ArcNode *pre,*p;for (i=0;i<G->n;i++)      //遍历所有的头结点{  pre=G->adjlist[i].firstarc;if (pre!=NULL){  p=pre->nextarc;while (p!=NULL)  //释放adjlist[i]的所有边结点{  free(pre);pre=p; p=p->nextarc;}free(pre);}}free(G);         //释放G所指的头结点数组的内存空间
}

2.4输出图运算算法

将图G的邻接表存储结构输出到屏幕上。

void DispGraph(AdjGraph *G)      //输出图的邻接表
{  ArcNode *p;int i;for (i=0;i<G->n;i++)       //遍历所有的头结点{ printf("  [%2d]",i);p=G->adjlist[i].firstarc; //p指向第一个相邻点 if (p!=NULL)printf(" →");while (p!=NULL){  printf(" %d(%d)",p->adjvex,p->weight);p=p->nextarc;      //p移向下一个相邻点}printf("\n");}
}

2.5求顶点度运算算法

对于无向图和有向图,求顶点度有所不同。依据定义,求无向图G中顶点v的度的算法如下:

int Degree1(AdjGraph *G,int v)   //求无向图G中顶点v的度
{  int d=0;ArcNode *p;if (v<0 || v>=G->n)return -1;  //顶点编号错误返回-1p=G->adjlist[v].firstarc;while (p!=NULL)   //统计v顶点的单链表中边结点个数即度{  d++;p=p->nextarc;}return d;
}int Degree2(AdjGraph *G,int v)  //求有向图G中顶点v的度
{  int i,d1=0,d2=0,d; ArcNode *p;if (v<0 || v>=G->n)return -1;         //顶点编号错误返回-1p=G->adjlist[v].firstarc;while (p!=NULL)       //统计v的单链表中边结点个数即出度{  d1++;p=p->nextarc;}for (i=0;i<G->n;i++)  //统计边结点中adjvex为v的个数即入度{  p=G->adjlist[i].firstarc;while (p!=NULL){  if (p->adjvex==v) d2++;p=p->nextarc;}}d=d1+d2;return d;
}

2.6 主函数

int main(int argc, char** argv)
{AdjGraph *G;int n=5,e=7,i;int A[MAXVEX][MAXVEX]={{0,1,2,6,INF},{INF,0,INF,4,5},{INF,INF,0,INF,3},{INF,INF,INF,0,INF},{INF,INF,INF,7,0}};CreateGraph(G,A,n,e);   //建立图7.4图的邻接表printf("图G的存储结构:\n"); DispGraph(G);printf("图G中所有顶点的度:\n"); printf("  顶点\t度\n");for (i=0;i<G->n;i++)printf("   %d\t%d\n",i,Degree2(G,i));DestroyGraph(G);return 0;
}

时间关系博主就不展示效果了,把这些代码复制过去就可以了

总结:

图的存储我们学习的差不多了,邻接矩阵就是一个存放顶点的数组和一个二维数组组成,二维数组用来下标用来表示顶点与顶点的边连接,有这条边就把这两个下标对于的数组赋值1,没有赋值0,邻接表就是有多个链表,一个用来保存头结点,每个头结点会指向一个链表,这个链表用来存顶点的数组的下标,**注:存头结点的链表是结构体数组类型的。**好了这篇文章博主就学完了,传作不易,点赞关注评论收藏,谢谢啦!!!

图的存储结构(邻接矩阵和邻接表)相关推荐

  1. 数据结构考研笔记(十五)——图的存储结构邻接矩阵、邻接表、十字链表、临界多重表的概念

    图的存储结构 1.邻接矩阵 1.1有向图 1.2无向图 2.邻接表法 2.1有向图边表 2.2无向图边表 3.十字链表 4.临界多重表 十字链表与临界多重表 1.邻接矩阵 邻接矩阵法结点数为n的图G ...

  2. 数据结构与算法(7-1)图的存储(邻接矩阵、邻接表)

    目录 一.图的邻接矩阵 存储结构 总代码 二.网图的邻接矩阵 存储结构 总代码 三.图的邻接表 存储结构 1.顶点列表结构体 2.邻接顶点结构体 总代码 四.网图的邻接表 存储结构 1.顶点列表结构体 ...

  3. 网状结构(图)图的存储(邻接矩阵、邻接表)、图的遍历(深度DFS、广度BFS)、图的最短路径

    图 多对多关系 是一种网状数据结构,图是由非空的顶点集合和一个描述顶点之间关系的集合组成 其定义 Graph = (V, E) V={x | x ∈某个数据对象} E = {<u, v> ...

  4. 图的两种存储方式---邻接矩阵和邻接表

    图:图是一种数据结构,由顶点的有穷非空集合和顶点之间边的集合组成,表示为G(V,E),V表示为顶点的集 合,E表示为边的集合. 首先肯定是要对图进行存储,然后进行一系列的操作,下面对图的两种存储方式邻 ...

  5. 一、图的定义,邻接矩阵和邻接表的实现

    目录 一.初识图 (1)图的定义 (2)图的分类 二.图的存储结构 (1)邻接矩阵 (2)邻接表(无向图) (3)其他 一.初识图 (1)图的定义 图(Graph)是由顶点的有穷非空集合(必须存在顶点 ...

  6. 图的链式存储结构解析(邻接表、逆邻接表、十字链表、邻接多重表)

    图的矩阵表示法比较消耗空间,需要花费$ n 2 n^2 n2$个单元存储边(弧).在边数较少的情况下比较浪费.我们这里来讨论图的链式存储结构. 图的链式结构主要有四类:邻接表.逆邻接表.十字链表.邻接 ...

  7. 图的创建(邻接矩阵和邻接表)

    编译环境:vs2019 图的遍历(深度优先和广度优先)          邻接矩阵 一:基本概念   邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵.设G= (V,E)是一个 ...

  8. 【数据结构笔记20】图的定义,图的表示:邻接矩阵与邻接表

    本次笔记内容: 6.1.1 什么是图 - 定义 6.1.2 什么是图 - 邻接矩阵表示法 6.1.3 什么是图 - 邻接表表示法 文章目录 图的定义 线性表与树可看做图的特殊实例 图包含 抽象数据类型 ...

  9. 图的介绍和邻接矩阵、邻接表的创建(以有向图为例)

    小编满血复活,更新力度感人~ 先让我们看看有向图长什么样吧 有向图是指节点与节点之间连线是有方向性的. 一.图的介绍 图分为有向图和无向图. 图由许多的节点组成,这些节点我们称为顶点. 有向图是指顶点 ...

  10. 7.2图的存储结构(邻接矩阵)

    邻接矩阵(无向图) 因为图是由顶点和边或弧组成的,所以最好是把他们分开存储. 下面来看无向图的邻接矩阵. 图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图. 如下图所示: ...

最新文章

  1. JAVA语法基础 3
  2. java org.jb2011报错_Java中getResourceAsStream()用法总结(转)
  3. 微信小程序开发--数据绑定
  4. 游戏编程中的数学——随机数字生成(RNG)的黑暗秘密
  5. 2.5 隐藏委托关系
  6. System variables, logging and the Execute SQL Task...(zz)
  7. 《Python Cookbook 3rd》笔记(4.15):顺序迭代合并后的排序迭代对象
  8. LeetCode 1971. Find if Path Exists in Graph(图的遍历)
  9. python哪本书好看_python入门看哪本书好
  10. c运算符优先级_C运算符
  11. PR开场片头视频模板 多帧城市闪点社交媒体短视频pr模板
  12. msfconsole理论
  13. revit二次开发之插件安装包制作
  14. 双下划线一粗一细怎么加_word 下划线 一粗一细
  15. js前端构造json对象后台接收并反序列化
  16. image库的使用笔记
  17. Linux中RAID5搭建
  18. 计算机的扩展模式,Win7双屏复制/双屏扩展设置教程
  19. 用一部电影让你了解综合实践活动课
  20. 一款高颜值开源知识管理工具

热门文章

  1. 记事中快速加当前日期时间
  2. 走出舒适区的两种方法
  3. android speex AEC 回音消除
  4. 赢在微点答案专区英语_英语u校园读写2答案unit3,u校园新标准大学英语视听说3单元测试答案搜题公众号...
  5. 同轴光的发光特征及其使用时的注意事项
  6. 阿松和阿柏无事闲聊互道岁月不饶人
  7. 只有毅力和决心无往不利
  8. 日本汽车氢能源行业的发展现状
  9. centos 安装 redis
  10. 面试轻松讲清楚 Java 面向对象的问题与知识(类与对象,封装,继承,多态,接口,内部类...)