C语言数据结构、十字链表的分析及实现

article/2025/11/9 13:15:36

目录

前言

一、什么是十字链表

二、认识十字链表

1.十字链表的组成

2.顶点和弧的连接

三、代码逻辑实现

1.出度

 2.入度

总结



前言

  无论是什么程序都要和数据打交道,一个好的程序员会选择更优的数据结构来更好的解决问题,因此数据结构的重要性不言而喻。数据结构的学习本质上是让我们能见到很多前辈在解决一些要求时间和空间的难点问题上设计出的一系列解决方法,我们可以在今后借鉴这些方法,也可以根据这些方法在遇到具体的新问题时提出自己的解决方法。(所以各种定义等字眼就不用过度深究啦,每个人的表达方式不一样而已),在此以下的所有代码都是仅供参考,并不是唯一的答案,只要逻辑上能行的通,写出来的代码能达到相同的结果,并且在复杂度上差不多,就行了。


一、什么是十字链表

在上篇文章的最后,我们分析了邻接表的优劣,邻接表本身并没有什么大的缺陷,如果说有缺点,那么是对于有向图而言对同时表示一个顶点的出度和入度麻烦,因为需要有邻接表和逆邻接表同时表示,而且这种应用场景是存在的。十字链表就是为了使这个问题得到解决而出现的。

所以十字链表就是一种将邻接表和逆邻接表结合在一起的一种图的存储结构,它针对的就是有向图中出度和入度一起使用的情况,并且大大节省了内存。

二、认识十字链表

1.十字链表的组成

十字链表是由数组+链表的形式构成的,数组用来记录顶点的信息,链表用来记录弧(边)的信息。

在有向图中,顶点集的存储结构如下图所示

其中data是数据域,用于记录顶点的信息,而firstIn和firstOut是两个指针,指向的是以该节点为弧头(In)或弧尾(Out)的第一节点。

 对于如此一个有向图而言,弧头和弧尾的概念是人为设置的,在这里我们假定一个顶点的入度指向弧头,出度的方向为弧尾

 它的顶点数组应该这么表示,为了方便讲解,这里我们假定输入的值就是对应的下标,实际上应该通过用户输入的值在顶点数组中找到对应的下标

代码实现

//顶点集
typedef struct VexNode
{//数据域int data;ArcBox* firstIn, *firstOut;//以该节点为弧头或弧尾的首节点
}VexNode;

 在有向图中每一个顶点与之对应的弧,具体的弧的存储结构如下所示

其中tailvex表示的是在这一条弧中弧尾节点在顶点数组中对应的下标,headvex表示的是在这一条弧中弧头节点在顶点数组中对应的下标;(实际上应该还有一个代表权值的元素weight,但这里不做描述)

代码实现

//边集(弧集)
typedef struct ArcBox
{int tailvex, headvex;//弧尾 弧头对应的顶点下标struct AcrBox* nextIn, *nextOut;//下一个相同尾节点的弧 下一个相同头节点的弧
}ArcBox;

然而在代码逻辑上,我们还是需要一个抽象结构,也就是可以用一个结构体把顶点集合与弧的集合联系在一起,构建十字链表

#define MAXVEX 200
typedef struct X
{//存储顶点的一维数组VexNode* Xlist[MAXVEX];int numV, numA;//顶点数 弧数
}OLGraph;

2.顶点和弧的连接

还是对于这样一个有向图,我们以节点V0为例,可以看到与V0有关的弧有四条,分别是:(V0,V1)、(V0,V2)、(V1,V0)、(V3,V0)因为这是一个有向图,所以我们应该以有向图的入度和出度的形式去观察V0节点,很明显(V0,V1)、(V0,V2)两条弧表示V0的出度,而(V1,V0)、(V3,V0)表示的是V0的入度

结合上文的描述,我们可以构建出这个有向图的顶点集合与弧集,我把它们具现化为如下图表

怎么理解这张图表呢?左边的图表表示的是从V0到V3的顶点的集合,data是V0到V3的值;右边的离散的表格代表的就是有向图中一条一条的弧,也就是每个顶点对应的弧的集合

我还是以V0为例,对于V0入度节点是V1和V3,出度节点是V1和V2,现在要根据上文的描述,把V0的顶点集合和与V0有关的弧的集合联系起来

 对于顶点集合的结构来说,firstOut应该指向V0的第一个出度节点,从逻辑上来说没有先后排序,但从代码上的步骤是遍历V0的所有的邻接点去判断,所以这里firstOut应该指向弧(V0,V1),如下图所示

 

 而在弧集中的结构来说,nextIn表示的是指向下一个相同尾节点的弧,对于弧(V0,V1)和弧(V0,V2)它们都是从V0开始,也就是它们有着同一个尾节点V0,所以弧(V0,V1)的nextIn应该指向的是弧(V0,V2)

对于顶点集合的结构来说,firstIn应该指向V0的第一个入度节点,从逻辑上来说没有先后排序,但从代码上的步骤是遍历V0的所有的邻接点去判断,所以这里firstIn应该指向弧(V1,V0),如下图所示

 

  而在弧集中的结构来说,nextOut表示的是指向下一个相同头节点的弧,也就是弧头所指向的都是V0的弧,即弧(V1,V0)的nextOut应该指向弧(V3,V0)

这个时候与顶点V0和其有关所有的弧都联系上了。其它的节点同理

三、代码逻辑实现

在代码逻辑上对上文描述的顶点和弧的连接采用了链表中的头插法,逻辑比较简单,不清楚的可以在纸上画一画就清楚了

黑线代表原来的连接,红线蓝色代表头插以后的连接)

1.出度

 ③

 2.入度

代码实现

void creatDG(OLGraph* G)
{int vi, vj;//输入有向图的顶点数和边数scanf_s("%d%d", &G->numV, &G->numA);//输入顶点集的数据for(int i = 0; i < G->numV; i++){scanf_s("%d", &G->Xlist[i]->data);G->Xlist[i]->firstIn = NULL;G->Xlist[i]->firstOut = NULL;}//构建十字链表for(int i = 0; i < G->numA; i++){//输入值 查找相对应的下标//这里就当直接输入下标scanf_s("%d%d", &vi, &vj);//建立弧的节点ArcBox* p = (ArcBox*)malloc(sizeof(ArcBox));p->tailvex = vi;p->tailvex = vj;//头插法插入新的边表节点pp->nextIn = G->Xlist[vj]->firstIn;//指向弧头相同的下一个弧p->nextOut = G->Xlist[vi]->firstOut;//指向弧尾相同的下一个弧G->Xlist[vi]->firstOut = G->Xlist[vj]->firstIn = p; }
}

总结

 全部代码

#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 200
//十字链表
//边集(弧集)
typedef struct ArcBox
{int tailvex, headvex;//弧尾 弧头对应的顶点下标struct AcrBox* nextIn, *nextOut;//下一个相同尾节点的弧 下一个相同头节点的弧
}ArcBox;
//顶点集
typedef struct VexNode
{//数据域int data;ArcBox* firstIn, *firstOut;//以该节点为弧头或弧尾的首节点
}VexNode;
//构建十字链表
typedef struct X
{//存储顶点的一维数组VexNode* Xlist[MAXVEX];int numV, numA;//顶点数 弧数
}OLGraph;void creatDG(OLGraph* G)
{int vi, vj;//输入有向图的顶点数和边数scanf_s("%d%d", &G->numV, &G->numA);//输入顶点集的数据for(int i = 0; i < G->numV; i++){scanf_s("%d", &G->Xlist[i]->data);G->Xlist[i]->firstIn = NULL;G->Xlist[i]->firstOut = NULL;}//构建十字链表for(int i = 0; i < G->numA; i++){//输入值 查找相对应的下标//这里就当直接输入下标scanf_s("%d%d", &vi, &vj);//建立弧的节点ArcBox* p = (ArcBox*)malloc(sizeof(ArcBox));p->tailvex = vi;p->tailvex = vj;//头插法插入新的边表节点pp->nextIn = G->Xlist[vj]->firstIn;//指向弧头相同的下一个弧p->nextOut = G->Xlist[vi]->firstOut;//指向弧尾相同的下一个弧G->Xlist[vi]->firstOut = G->Xlist[vj]->firstIn = p; }
}

如果在一个项目中,需要频繁的对一个图的边(弧)增删改查呢?那么对十字链表来说增加或删除一条边有可能就会牵一发而动全身呢?是不是操作很麻烦?这就是十字链表的缺点,那么又存在什么样的结构可以解决上述问题呢?我们下一篇文章再解析。


http://chatgpt.dhexx.cn/article/wQysrbhA.shtml

相关文章

JS 数据结构:链表

单链表 每个节点中只包含一个指针域的链表称为单链表。 头结点—其指针域指向表中第一个结点的指针&#xff08;头结点不是必须的&#xff0c;只是习惯上加上头结点&#xff0c;而头结点的数据域一般记录的是该链表的相关数据&#xff0c;如&#xff1a;链表长度&#xff09;…

数据结构中链表和列表的区别

顺序表和链表由于存储结构上的差异&#xff0c;导致它们具有不同的特点&#xff0c;适用于不同的场景。通过系统地学习顺序 表和链表我们知道&#xff0c;虽然它们同属于线性表&#xff0c;但数据的存储结构有本质的不同。 • 顺序表存储数据&#xff0c;需预先申请一整块足够…

数据结构(六)——循环链表

一、循序链表简介 1、循环链表的定义 循环链表的任意元素都有一个前驱和一个后继&#xff0c;所有数据元素在关系上构成逻辑上的环。 循环链表是一种特殊的单链表&#xff0c;尾结点的指针指向首结点的地址。 循环链表的逻辑关系图如下&#xff1a; 2、循环链表的设计实现 …

数据结构-使用链表实现栈

目录结构 Stack接口 package LinkedListStack;public interface Stack<E> {int getSize();boolean isEmpty();void push(E e); //向栈中添加元素E pop();//向栈中取出元素E peek();//查看栈顶的元素 }LinkedList类 package LinkedListStack;public class LinkedList<…

数据结构 | 链表的实现

目录 单链表双链表数组结构和链式结构的对比 线性表中&#xff0c;除了顺序表这一重要的结构&#xff0c;还有链式结构&#xff0c;而这也是我们常说的链表。 一般是通过定义结构体(类)的方式来表示链表的每一个结点。一般而言&#xff0c;链表的结点都会有数据域和地址域。数据…

Java数据结构之链表

目录 一.单链表 1.单链表的介绍和内存布局 2.单链表的添加和遍历 3.单链表的插入 4.单链表的删除 二.双向链表 1.添加节点 2.遍历节点 3.插入节点 4.删除结点 5.测试 三.单向环形链表 1.问题的引出 ​编辑 2.构建环形链表 1.创建结点 3.测试 3.约瑟夫问题代码的…

c++数据结构:链表

链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包括两个部分&#xff1a;一个是…

java数据结构-链表详解

文章目录 1.数据结构-链表详解1.1单链表1.1.1单链表节点的尾部添加1.1.2单链表节点的自动排序添加1.1.3单链表节点的修改1.1.4单链表节点的删除 1.2单链表面试题1.2.1单链表的有效节点个数1.2.2单链表倒数第k个结点1.2.3单链表反转1.2.4单链表逆序打印 1.3双向链表1.3.1双向链表…

C语言数据结构链表(图文)

目录 一、链表的简单理解与引入 1.1 链表的引入 1.2 节点的理解 1.3 链表的分类 二、常用链表功能的实现 2.1 首先是节点的定义&#xff0c; 2.2 节点的创建 2.3 单链表的尾插 2.4 单链表的尾删 2.5 单链表的头插 2.6 链表的头删 2.7 单…

【数据结构】链表的学习总结

目录 1.链表的概念2.链表的结构1️⃣链表中单个结点的结构2️⃣链表的整体结构 3.链表的分类4.链表的实现1️⃣单向无头非循环2️⃣双向带头循环 1.链表的概念 链表&#xff0c;是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针…

C++数据结构之链表(详解)

主要参考文章地址 01.链表基础知识 | 算法通关手册 (itcharge.cn)&#xff09; 本次内容是对链表的总结&#xff0c;可以看了上面的文章之后。 在看我下面的内容&#xff0c;做一个简短的复习&#xff0c;且本内容的代码均用C实现&#xff0c;而参考资料的代码则为python。 …

[数据结构]链表之单链表(详解)

文章目录 [数据结构]链表之单链表前言1.链表1.1链表的概念及结构1.2单链表与顺序表的区别与优缺点1.3八种链表类型、单向带头循环链表单向带头非循环链表单向不带头循环链表单向不带头非循环链表双向带头循环链表双向带头非循环链表双向不带头循环链表双向不带头非循环链表 2.单…

【数据结构与算法】详解什么是链表,并用代码手动实现一个链表结构

本系列文章【数据结构与算法】所有完整代码已上传 github&#xff0c;想要完整代码的小伙伴可以直接去那获取&#xff0c;可以的话欢迎点个Star哦~下面放上跳转链接 https://github.com/Lpyexplore/structureAndAlgorithm-JS 本文将来讲解一下一种常见的线性数据结构—链表&a…

数据结构-链表篇

数据结构中数组和链表是是使用频率最高的基础数据结构。数组作为数据存储结构有一定的缺陷。在无序数组中&#xff0c;搜索性能差&#xff0c;在有序数组中&#xff0c;插入效率又很低&#xff0c;而且这两种数组的删除效率都很低&#xff0c;并且数组在创建后&#xff0c;其大…

数据结构之——链表

目录 一、链表的概念及结构 二、单链表的实现&#xff08;无头单向非循环链表&#xff09; 1.单链表节点定义 2.单链表的接口实现 &#xff08;1&#xff09;动态申请一个节点 &#xff08;2&#xff09;单链表打印 &#xff08;3&#xff09;单链表的销毁 &#xff0…

【数据结构】链表

单链表 这张图是我们待会要实现的功能&#xff0c;我会尽可能的将每一步都说的很详细&#xff0c;方便理解。 链表的概念及结构 概念&#xff1a;链表是一种 物理存储结构上非连续 、非顺序的存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 指针链 接 次序实现的 。…

数据结构之链表

目录 一、链表的特点 二、虚拟头结点 三、链表的实现 1、定义LinkedList 2、 构造方法 3、基本方法 4、添加元素 5、查找元素 6、修改元素 7、删除元素 链表是一种物理存储单元上非连续、非顺序的数据结构。前几篇我们讲到的数组也好&#xff0c;基于数组实现的栈…

[数据结构] 链表(图文超详解讲解)

文章目录 一、链表是什么&#xff1f;二、链表 1.链表的结构2.链表方法的代码实现总结 一、链表是什么&#xff1f; 链表是一种物理存储结构上非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 二、链表 1.链表的结构 链表的结构如图: 链…

数据结构---单向链表,双向链表,单向环形链表

链表介绍 链表是以节点的方式来存储,是链式存储每个节点包含 data 域&#xff0c; next 域:指向下一个节点.如图:发现链表的各个节点不一定是连续存储.链表分带头节点的链表和没有头节点的链表&#xff0c;根据实际的需求来确定 修改节点功能 思路(1) 先找到该节点&#xff0c…

数据结构与算法——线性表(链表篇)

&#x1f60a;数据结构与算法——线性表&#xff08;链表篇&#xff09; &#x1f680;前言&#x1f680;线性链表&#xff08;单链表&#xff09;&#x1f6a2;概念&#x1f6a2;基本操作&#x1f47b;插入操作⛅按位序插入⛅指定结点的后插操作⛅指定节点的前插操作 &#x1…