用邻接表存储图c语言,邻接表、邻接多重表、十字链表及C语言实现
上一节介绍了如何使用顺序存储结构存储邻接多重表和
邻接的意思是顶点之间有边或者弧存在,通过当前顶点,可以直接找到下一个顶点。
邻接表
使用邻接表存储图时,对于图中的每一个顶点和它相关的邻接点,都存储到一个链表中。每个链表都配有头结点,头结点的数据域不为NULL,而是用于存储顶点本身的数据;后续链表中的各个结点存储的是当前顶点的所有邻接点。
所以,采用邻接表存储图时,有多少顶点就会构建多少个链表,为了便于管理这些链表,常用的方法是将所有链表的链表头按照一定的顺序存储在一个
图 1 表结点结构
info 域对于无向图来说,本身不具备权值和其它相关信息,就可以根据需要将之删除。
例如,当存储图 2(A)所示的有向图时,构建的邻接表如图 2(B)所示:
图 2 有向图和对应的邻接表
邻接表存储图的存储结构为:
#define MAX_VERTEX_NUM 20//最大顶点个数
#define VertexType int//顶点数据的类型
#define InfoType int//图中弧或者边包含的信息的类型
typedef struct ArcNode{
int adjvex;//邻接点在数组中的位置下标
struct ArcNode * nextarc;//指向下一个邻接点的指针
InfoType * info;//信息域
}ArcNode;
typedef struct VNode{
VertexType data;//顶点的数据域
ArcNode * firstarc;//指向邻接点的指针
}VNode,AdjList[MAX_VERTEX_NUM];//存储各链表头结点的数组
typedef struct {
AdjList vertices;//图中顶点及各邻接点数组
int vexnum,arcnum;//记录图中顶点数和边或弧数
int kind;//记录图的种类
}ALGraph;
邻接表计算顶点的度
使用邻接表存储无向图时,各顶点的度为各自链表中包含的结点数;存储有向图时,各自链表中具备的结点数为该顶点的出度。求入度时,需要遍历整个邻接表中的结点,统计数据域和该顶点数据域相同的结点的个数,即为顶点的入度。
对于求有向图中某结点的入度,还有一种方法就是再建立一个逆邻接表,此表只用于存储图中每个指向该顶点的所有的顶点在数组中的位置下标。例如,构建图 2(A)的逆邻接表,结果为:
图 3 逆邻接表
对于具有 n 个顶点和 e 条边的无向图,邻接表中需要存储 n 个头结点和 2e 个表结点。在图中边或者弧稀疏的时候,使用邻接表要比前一节介绍的邻接矩阵更加节省空间。
十字链表
十字链表存储的对象是有向图或者有向网。同邻接表相同的是,图(网)中每个顶点各自构成一个链表,为链表的首元结点。同时,对于有向图(网)中的弧来说,有弧头和弧尾。一个顶点所有的弧头的数量即为该顶点的入度,弧尾的数量即为该顶点的出度。每个顶点构成的链表中,以该顶点作为弧头的弧单独构成一个链表,以该顶点作为弧尾的弧也单独构成一个链表,两个链表的表头都为该顶点构成的头结点。
这样,由每个顶点构建的链表按照一定的顺序存储在数组中,就构成了十字链表。
所以,十字链表中由两种结点构成:顶点结点和弧结点。各自的结构构成如下图所示:
图 4 十字链表的结点构成
弧结点中, tailvex 和 headvex 分别存储的是弧尾和弧头对应的顶点在数组中的位置下标; hlink 和 tlink 为指针域,分别指向弧头相同的下一个弧和弧尾相同的下一个弧; info 为指针域,存储的是该弧具有的相关信息,例如权值等。
顶点结点中,data 域存储该顶点含有的数据; firstin 和 firstout 为两个指针域,分别指向以该顶点为弧头和弧尾的首个弧结点。
图 5 有向图及其十字链表
例如,使用十字链表存储有向图 5(A) ,构建的十字链表如图 (B) 所示,构建代码实现为:
#define MAX_VERTEX_NUM 20
#define InfoType int//图中弧包含信息的数据类型
#define VertexType int
typedef struct ArcBox{
int tailvex,headvex;//弧尾、弧头对应顶点在数组中的位置下标
struct ArcBox *hlik,*tlink;//分别指向弧头相同和弧尾相同的下一个弧
InfoType *info;//存储弧相关信息的指针
}ArcBox;
typedef struct VexNode{
VertexType data;//顶点的数据域
ArcBox *firstin,*firstout;//指向以该顶点为弧头和弧尾的链表首个结点
}VexNode;
typedef struct {
VexNode xlist[MAX_VERTEX_NUM];//存储顶点的一维数组
int vexnum,arcnum;//记录图的顶点数和弧数
}OLGraph;
int LocateVex(OLGraph * G,VertexType v){
int i=0;
//遍历一维数组,找到变量v
for (; ivexnum; i++) {
if (G->xlist[i].data==v) {
break;
}
}
//如果找不到,输出提示语句,返回 -1
if (i>G->vexnum) {
printf("no such vertex.\n");
return -1;
}
return i;
}
//构建十字链表函数
void CreateDG(OLGraph *G){
//输入有向图的顶点数和弧数
scanf("%d,%d",&(G->vexnum),&(G->arcnum));
//使用一维数组存储顶点数据,初始化指针域为NULL
for (int i=0; ivexnum; i++) {
scanf("%d",&(G->xlist[i].data));
G->xlist[i].firstin=NULL;
G->xlist[i].firstout=NULL;
}
//构建十字链表
for (int k=0;karcnum; k++) {
int v1,v2;
scanf("%d,%d",&v1,&v2);
//确定v1、v2在数组中的位置下标
int i=LocateVex(G, v1);
int j=LocateVex(G, v2);
//建立弧的结点
ArcBox * p=(ArcBox*)malloc(sizeof(ArcBox));
p->tailvex=i;
p->headvex=j;
//采用头插法插入新的p结点
p->hlik=G->xlist[j].firstin;
p->tlink=G->xlist[i].firstout;
G->xlist[j].firstin=G->xlist[i].firstout=p;
}
}
对于链表中的各个结点来说,由于表示的都是该顶点的出度或者入度,所以结点之间没有先后次序之分,程序中构建链表对于每个新初始化的结点采用头插法进行插入。
十字链表计算顶点的度
采用十字链表表示的有向图,在计算某顶点的出度时,为 firstout 域链表中结点的个数;入度为 firstin 域链表中结点的个数。
邻接多重表
使用邻接表解决在无向图中删除某两个结点之间的边的操作时,由于表示边的结点分别处在两个顶点为头结点的链表中,所以需要都找到并删除,操作比较麻烦。处理类似这种操作,使用邻接多重表会更合适。
邻接多重表可以看做是邻接表和十字链表的结合体。和十字链表唯一不同的是顶点结点和表结点的结构组成不同;同邻接表相比,不同的地方在于邻接表表示无向图中每个边都用两个结点,分别在两个不同链表中;而邻接多重表表示无向图中的每个边只用一个结点。
邻接多重表的顶点结点和表结点的构成如图 6 所示:
图 6 邻接多重表
表结点构成:
mark 为标志域,作用是标记某结点是否已经被操作过,例如在遍历各结点时, mark 域为 0 表示还未遍历;mark 域为 1 表示该结点遍历过;
ivex 和 jvex 分别表示该结点表示的边两端的顶点在数组中的位置下标; ilink 指向下一条与 ivex 相关的边;
jlink 指向下一条与 jvex 相关的边;
info 指向与该边相关的信息。
顶点结点构成:
data 为该顶点的数据域;
firstedge 为指向第一条跟该顶点有关系的边。
图 7 无向图及对应的邻接多重表
例如,使用邻接多重表表示图 7中左边的无向图时,与之相对应的邻接多重表如图右侧所示。
邻接多重表的存储结构用代码表示为:
#define MAX_VERTEX_NUM 20 //图中顶点的最大个数
#define InfoType int //边含有的信息域的数据类型
#define VertexType int //图顶点的数据类型
typedef enum {unvisited,visited}VisitIf; //边标志域
typedef struct EBox{
VisitIf mark; //标志域
int ivex,jvex; //边两边顶点在数组中的位置下标
struct EBox * ilink,*jlink; //分别指向与ivex、jvex相关的下一个边
InfoType *info; //边包含的其它的信息域的指针
}EBox;
typedef struct VexBox{
VertexType data; //顶点数据域
EBox * firstedge; //顶点相关的第一条边的指针域
}VexBox;
typedef struct {
VexBox adjmulist[MAX_VERTEX_NUM];//存储图中顶点的数组
int vexnum,degenum;//记录途中顶点个数和边个数的变量
}AMLGraph;
总结
本节介绍了有关图的三种链式存储结构:邻接表、十字链表和邻接多重表。
邻接表适用于所有的图结构,无论是有向图(网)还是无向图(网),存储结构较为简单,但是在存储一些问题时,例如计算某顶点的度,需要通过遍历的方式自己求得。
十字链表适用于有向图(网)的存储,使用该方式存储的有向图,可以很容易计算出顶点的出度和入度,只需要知道对应链表中的结点个数即可。
邻接多重表适用于无向图(网)的存储,该方式避免了使用邻接表存储无向图时出现的存储空间浪费的现象,同时相比邻接表存储无向图,更方便了某些边操作(遍历、删除等)的实现。
用邻接表存储图c语言,邻接表、邻接多重表、十字链表及C语言实现相关推荐
- 邻接表存储图的广度优先遍历
试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ); 其中LGraph是邻接表存储 ...
- 邻接表存储图利用BFS遍历
//今天上机写的邻接表存储图利用BFS遍历: #include<stdio.h> #include<stdlib.h> #include<string.h> #in ...
- 采用邻接矩阵形式存储图,进行图的深度优先搜索并输出结果。
内容: 采用邻接矩阵形式存储图,进行图的深度优先搜索并输出结果. 步骤: 算法分析 本题需要利用邻接矩阵的形式存储图,并对图进行深度优先搜索并输出结果.大体上可以分为两个部分,一是采用邻接矩阵的方式存 ...
- 数据结构——十字链表(C语言实现)
十字链表是将邻接表和逆邻接表结合在一起的一种有向图的数据结构 十字链表的节点结构体表示的是一个节点到另一个节点的边,并且此由指出节点(from)和指入节点(to)共同使用,因此大大节省了内存. 先直观 ...
- 【2 - 数据库是如何存储数据的】Sql Server - 郝斌(字段、记录、表;图形化界面及sql语句建表;六种约束;一对一、一对多、多对多、数据库关系图;主外键)
课程地址:数据库 SQLServer 视频教程全集(99P)| 22 小时从入门到精通_哔哩哔哩_bilibili 目录 数据库是如何解决数据存储问题的 1. 表的相关数据 2. create tab ...
- c语言 链表_C语言编程第22讲——单向有序链表的C语言实现
1.单向有序链表的含义 单向有序链表可以解析为四个名词: 表:一组元素: 链表:表中的元素不是从前往后一个挨着一个,而是通过一个元素才能找到另一个元素: 单向:表中的元素只能从前往后访问: 有序:表中 ...
- mysql 邻接表_图的邻接表存储结构详解
通常,图更多的是采用链表存储,具体的存储方法有 3 种,分别是邻接表.邻接多重表和十字链表. 本节先讲解图的邻接表存储法.邻接表既适用于存储无向图,也适用于存储有向图. 在具体讲解邻接表存储图的实现方 ...
- 数据结构之图的存储结构:邻接多重表
图的存储结构:邻接多重表 产生条件: 邻接多重表的定义: 邻接多重表的代码定义: 删除: 性能分析: 十字链表与邻接多重表的对比 产生条件: 当用邻接矩阵法存储时:空间复杂度为O(|V|^2),太大 ...
- 7.2图的存储结构(十字链表、邻接多重表、边集数组)
思路: 有没有可能把邻接表和逆邻接表结合起来. 所以就产生了十字链表(Orthogonal List) 为此我们重新定义顶点表结点结构: data firstIn firstOut firstIn:第 ...
最新文章
- mysql,int(5)、int(10)啥区别联系
- 创建与合并分支-git入门教程
- html表单的常用属性有哪些,html/form表单常用属性认识
- NFS服务的配置过程
- 第58课 百钱买百鸡(完整) 3.完善程序 (《小学生C++趣味编程》)
- python怎么切图片_Python切割图片成九宫格
- 用另一种方式来讲解代理模式~
- 毕设日志——pytorch版本faster rcnn运行代码前的环境配置2019.4.9
- 企业级容器镜像仓库Harbor的搭建
- 禅道备份功能_禅道数据库备份
- NonComVisibleBaseClass Exception
- css 设置input输入内缩进
- cisco的路由器上rip的被动接口,单播更新,水平分隔
- php对象在内存中的分配
- 三维激光LiDAR点云数据处理,我帮您!
- 《勿忘初心,勿忘前行》——2016年度总结
- linux常用命令(2)关机重启 文本编辑器 系统管理 软件安装
- git push出现 remote: Support for password authentication was removed on August 13, 2021.
- Eclipse中Outline里各种图标的含义
- Vue前端模板框架--vue-admin-template
热门文章
- 解决 Win10 无法开启任务栏右键软件打开最近项目的问题
- 网页移动端给页面横屏提示
- 虹科智能汽车诊断及智能汽车测试联合实验室成立
- hive的条件查询语句_Hive SQL 条件函数 IF 详解
- 短链接网址是如何生成的?
- 学习 Bootstrap 5 之 Typography
- windows camera frame server内存占用过大问题
- 关于 Bitmap.createScaledBitmap(); 重新生成新的bitmap 问题
- 用html+javascript打造公文一键排版系统1:设计界面
- mysql修改字段卡住问题总结