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

【数据结构——十字链表】

引入

在邻接矩阵之后,为了提升空间利用率而引出了邻接表。邻接表适用于计算有向图中顶点的出度数、逆邻接表适用于计算有向图中顶点的入度数。十字链表可以同时满足这两个要求。

十字链表是一种用于表示有向图的数据结构,它的核心特点是将“以弧尾为线索的链表”和“以弧头为线索的链表”交叉结合:

  • 每条弧(有向边)同时属于两个链表:一个是以其弧尾顶点为起点的“出边链表”,另一个是以其弧头顶点为终点的“入边链表”。
  • 这种“交叉链表”的结构,让它能高效地处理有向图的入度、出度查询,以及弧的增删操作,因此命名为 CrossLinkGraph (十字链接图)。

十字链表的优缺点

  • 优点:
    适合稀疏矩阵的高效存储,节省空间。
    支持快速按行或按列遍历非零元素。
  • 缺点:
    实现复杂度较高,需维护双向链表。
    随机访问元素性能较差,需遍历链表

结构示图

在这里插入图片描述

tNext表示的是除head之外以tail为弧尾的弧头节点。
同样,hNext表示的是除tail之外以head为弧头的弧尾节点。

例图:
在这里插入图片描述

对应结构模型:

在这里插入图片描述
每个弧(有向边)用一个 ArcBox 节点表示,每个顶点用包含 firstIn (入度链头)和 firstOut (出度链头)的节点表示。

上图结构模型中的实线代表出边(从当前顶点指出去,即当前节点做为弧尾),虚线代表入边(从其他节点指向当前顶点,即当前节点做为弧头)。
--------------------------------------------------------------------------------------------------------------

例如(为方便观察下面贴的图片是重复的):

  • 实线部分
    v0的节点结构中firstOut指向的边结构是以v0为弧尾的,以v0为弧尾的节点是v3,所以边结构中head为v3,tNext表示除v3之外仍然以v0为弧尾的节点,显然没有了,所以只能为空。
    在这里插入图片描述

  • 虚线部分
    v0的firstIn就是当v0作为弧头被其他节点指向时的数据,它表示的是指向v0的节点,也就是以v0为弧头的弧尾节点。v1,v2就是这样的节点,按次序进行指向,所以v0的firstIn就指向以v1为弧尾的弧头位置(还是v0)。而hNext就是指向除v1之外且以v0作为弧头的弧尾节点的边结构,这里是v0与v2节点之间的,则hNext就指向以v0作为弧头,v2为弧尾的边结构的hNext(方便再次寻找以v0作为弧头的弧尾节点的其他节点)。找到这里对于v0就没有满足条件的节点了,所以hNext指向空。

注意:在十字链表中,同一条弧(有向边)会同时出现在“出边链表”和“入边链表”中:

  • 从弧尾顶点的角度,这条弧是“出边”,存储在 firstOut 链表中;
  • 从弧头顶点的角度,这条弧是“入边”,存储在 firstIn 链表中。

但本质上,这是同一块内存( ArcBox 结构体)被两个链表指针同时引用。因此 releaseCrossGraph只通过“出边/或入边链表”遍历(下面采用的是出边遍历)并释放所有弧的内存,同时保证了内存的不重复释放。

头文件

#pragma once
//十字链表的边结构
typedef struct arcBox{int tailVertex;struct arcBox* tailNext;int headVertex;struct arcBox* headNext;int weight;
}ArcBox;//十字链表的顶点结构
typedef struct {int no;const char* show;ArcBox* firstIn;  //该节点的入度ArcBox* firstOut; //该节点的出度
}CrossVertex;//利用十字链表的结构实现图结构
typedef struct {CrossVertex* nodes;int numVertex;int numEdge;
}CrossGraph;CrossGraph* createCrossGraph(int n);
void releaseCrossGraph(CrossGraph* graph);void initCrossGraph(CrossGraph* graph, const char* names[], int num);
void addCrossArc(CrossGraph* graph, int tail, int head, int w);//计算编号为no的节点的入度
int inDegreeCrossGraph(const CrossGraph* graph, int no);
//计算编号为no的节点的出度
int outDegreeCrossGraph(const CrossGraph* graph, int no);

功能实现

创建
CrossGraph* createCrossGraph(int n) {CrossGraph* graph = (CrossGraph*)malloc(sizeof(CrossGraph));if (graph == NULL)return NULL;graph->nodes = (CrossVertex*)malloc(sizeof(CrossVertex)*n);if (graph->nodes == NULL){free(graph);return NULL;}graph->numEdge = 0;graph->numVertex = n;return graph;
}
释放
void releaseCrossGraph(CrossGraph* graph) {int numEdges = 0;  //依次释放:边,节点,图if (graph) {if (graph->nodes) {for (int i = 0; i < graph->numVertex; i++) {ArcBox* box = graph->nodes[i].firstOut;ArcBox* tmp;while (box) {tmp = box;box = box->tailNext;free(tmp);numEdges++;}}printf("released %d edges\n", numEdges);free(graph->nodes);}free(graph);}
}
初始化

void initCrossGraph(CrossGraph* graph, const char* names[], int num) {for (int i = 0; i < num; ++i) {graph->nodes[i].no = i;graph->nodes[i].show = names[i];graph->nodes[i].firstIn = graph->nodes[i].firstOut = NULL;}
}
添加边
//添加一条以tail为弧尾,以head为弧头的边
void addCrossArc(CrossGraph* graph, int tail, int head, int w) {ArcBox* box = (ArcBox*)malloc(sizeof(ArcBox));if (box==NULL)return ;box->weight = w;//从出度关系上进行插入(头插法)box->tailVertex = tail;box->tailNext = graph->nodes[tail].firstOut;graph->nodes[tail].firstOut = box;//从入度关系上进行插入(头插法)box->headVertex = head;box->headNext = graph->nodes[head].firstIn;graph->nodes[head].firstIn = box;
}
计算入度
int inDegreeCrossGraph(const CrossGraph* graph, int no) 
{int count = 0;ArcBox* box = graph->nodes[no].firstIn;while (box!=NULL) {count++;box = box->headNext;}return count;
计算出度
int outDegreeCrossGraph(const CrossGraph* graph, int no) {int count = 0;ArcBox* box = graph->nodes[no].firstOut;while (box) {count++;box = box->tailNext;}return count;
}

功能调用

void setupCrossGraph(CrossGraph* graph) {const char* nodeName[] = {"v0","v1","v2","v3"};initCrossGraph(graph, nodeName, 4);addCrossArc(graph, 0, 3, 1);addCrossArc(graph, 1, 0, 1);addCrossArc(graph, 1, 2, 1);addCrossArc(graph, 2, 0, 1);addCrossArc(graph, 2, 1, 1);
}int main() {int n = 4;CrossGraph* graph = createCrossGraph(n);if (graph == NULL) {return -1;}setupCrossGraph(graph);printf("V0的入度:%d\n", inDegreeCrossGraph(graph, 2));printf("V0的出度:%d\n", outDegreeCrossGraph(graph, 2));releaseCrossGraph(graph);return 0;
}

在这里插入图片描述

http://www.dtcms.com/a/420474.html

相关文章:

  • JSON-LD 的格式
  • 有域名怎么发布网站吗中企动力网站报价
  • 新网站怎么做流畅wordpress更新机制
  • 网站开发 流程图搜索引擎营销的原理是什么
  • 生成论坛网站自己建网站怎么做影视资源
  • 怎么免费搭建属于自己的网站做视频网站需要
  • 第三十七天:2025 图形绘制
  • Machine Mental Imagery: Empower MultimodalReasoning with Latent Visual Tokens
  • 新乡公司做网站机关网页设计价格表
  • 江阴网站建设推广网页制作基础教程9787121095306教案
  • API接口获取商品详情的实战运用(以淘宝平台为例)
  • JDK17新特性
  • 在福州做搬家网站多少钱全网营销推广定义
  • 有哪些做海报的网站网页游戏网站建设
  • node安装及解决“node’不是内部或外部命令,也不是可运行的程序戈批处理文件”问题
  • 上海网站建设报价方案短链接在线生成器
  • 用织梦系统做网站产权中国菲律宾直播
  • 益阳一站式网站建设公司淘宝网站建设的公司
  • 网站建设杭州哪家便宜网站优化包括
  • Kimi OK Computer实测:对话生成网站,PPT和仪表盘
  • 自然语言处理项目之情感分析(下)
  • 简墨博客系统测试报告
  • 数码港 太原网站开发公司小程序自己制作流程
  • 长春做网站长春网站设计如何开展网络营销推广
  • 界面设计好看的网站网页设计与制作步骤流程
  • 电商数据分析之自动获取数据的技术手段分享
  • 怎样用ps做企业网站wordpress配置qq邮件
  • 沈阳世纪兴网站制作公司电子书店网站开发
  • *Linux磁盘管理全攻略:LVM+RAID+文件系统指南
  • 【复习】计网每日一题--零窗口要启动的计时器