【详解】稀疏矩阵的十字链表✿◡‿◡

目录

引言:

稀疏矩阵的十字链表表示

第一步:创结点存数据

第二步:将头结点同数据结点串起来

第三步:创建一个总头结点构成循环链表

总代码如下:

运行结果如下:

结语:


引言:

接上一小结稀疏矩阵的三元组表示(循序表表示),一般有循序表示就有链表表示,今天我们要介绍的就是稀疏矩阵的链表表示✔✔✔

稀疏矩阵的十字链表表示

十字链表是稀疏矩阵的一种链式存储结构(我前一章写的三元组循序表是稀疏矩阵的一种循序存储结构),如果对三元组不了解的同学可以去我前面一章先看(超详细✌)

接着让我们进入十字链表的创建步骤

为了方便大家理解我先给出图片大家可以先看看,行和列都到h【5】

第一步:创结点存数据

既然是链表那么就一定有结点,对于稀疏矩阵中的每个非零元素创建一个结点存放它,存放的数据包括(1)元素行数(2)元素列数(3)元素值

代码如下 (因为增加通用性,故用ElemType方便修改)

union里面有value 和 link两个数据,其中value是存放数据结点的元素值,link是头结点的下一个结点,这里就体现了头结点的重要性,头结点-->link就是下一个结点,头结点-->right就是数据节点了,这样就可以把头结点和数据结点区分开来。

typedef int ElemType;
typedef struct mtxn 
{ 
	int row;					//行号
	int col;					//列号
   	struct mtxn *right,*down;	//向右和向下的指针
	union 
	{
		ElemType value;
		struct mtxn *link;
	} tag;
} MatNode;			//十字链表类型

第二步:将头结点同数据结点串起来

将同一行所有结点串成一个带头结点的循环单链表,将同一列所有结点串成一个带头结点的循环单链表,那么这里我们是不是可以合并呢,将行和列头结点放在一个数据结构里,这样是不是能跟方便一些呢,故我们只需创建MAX(行,列)个结点数,里面有行结点和列结点,这里是用right和down来实现的,头结点始终就那MAX(行,列)个,这里要好好理解。

void CreatMat(MatNode *&mh,ElemType a[][N])	//创建a的十字链表
{
	int i,j;
	MatNode *h[Max],*p,*q,*r;
	mh=(MatNode *)malloc(sizeof(MatNode));//创建十字链表的头结点
	mh->row=M;mh->col=N;
	r=mh;					//r指向尾结点
	for (i=0;i<Max;i++)		//采用尾插法创建头结点h1,h2,…循环链表
	{
		h[i]=(MatNode *)malloc(sizeof(MatNode));
		h[i]->down=h[i]->right=h[i];		//将down和right方向置为循环的
		r->tag.link=h[i];					//将h[i]加到链表中
		r=h[i];
	}
	r->tag.link=mh;							//置为循环链表
	for (i=0;i<M;i++)						//处理每一行
	{
		for (j=0;j<N;j++)					//处理每一列
		{
			if (a[i][j]!=0)					//处理非零元素
			{
				p=(MatNode *)malloc(sizeof(MatNode));	//创建一个新结点
				p->row=i;p->col=j;p->tag.value=a[i][j];
				q=h[i];      					//查找在行表中的插入位置
                while (q->right!=h[i] && q->right->col<j) 
                  	q=q->right;
				p->right=q->right;q->right=p;	//完成行表的插入
				q=h[j];      					//查找在列表中的插入位置
				while (q->down!=h[j] && q->down->row<i) 
					q=q->down;
				p->down=q->down;q->down=p;  	//完成列表的插入
			}
		}
	}
}

第三步:创建一个总头结点构成循环链表

创建一个总头结点方便进行插入删除的各种操作,并有利于查找数据,大家在刷力扣题时,有碰到链表一般都要自己创建一个头结点。

图画如下

以上便是稀疏矩阵的十字链表的创建方法。

创建完那么我们就要开始学习它的基本运算啦~~~~~🎉🎉🎉


创建上面已经给出故这里跳过

void DestroyMat(MatNode *&mh)        //销毁十字链表

一定要注意先后顺序,先释放数据结点再释放头结点循序不能乱,不然内存会泄露(不要内存泄漏🙅‍),最后不要忘了要把总结点free掉哦。

void DestroyMat(MatNode *&mh)		//销毁十字链表
{
	MatNode *pre,*p,*mp;
	mp=mh->tag.link;				//mp指向h[i]
	while (mp!=mh)					//释放所有数据结点
	{
		pre=mp->right;				//pre指向h[i]的行首结点
		if (pre!=mp)				//h[i]不空
		{
			p=pre->right;			//p指向结点pre的后继结点
			while (p!=mp)
			{
				free(pre);
				pre=p; p=p->right;
			}
		}
		mp=mp->tag.link;			//mp指向下一个头结点
	}
	//释放所有的头结点
	pre=mh->tag.link;				//pre指向h[i]
	p=pre->tag.link;				//p指向h[i+1]
	while (p!=mh)
	{
		free(pre);
		pre=p; p=p->tag.link;
	}
	free(mh);
}

void DispMat(MatNode *mh)        //输出十字链表

这应该是大家最希望看到的吧,不然我们这么知道我们到底做了些上面呢

注意注意这里是按行开始打印,可以按列哦

用一个循环将所有数据全部输出即可

void DispMat(MatNode *mh)		//输出十字链表
{
	MatNode *p,*q;
	printf("行=%d  列=%d\n", mh->row,mh->col);
	p=mh->tag.link;
	while (p!=mh) 
	{	
		q=p->right;
		while (p!=q) 		//输出一行非零元素
		{
			printf("%d\t%d\t%d\n", q->row,q->col,q->tag.value);
			q=q->right;
		}
		p=p->tag.link;
	}
}

总代码如下:

先创建再打印后销毁,前面最开头一定不要忘了头文件,和#define各项数据哦👌

创建是先头结点后数据结点,销毁是先数据结点后头结点,打印是用头结点去找数据结点,并按照行或列进行打印。

#define  _CRT_SECURE_NO_WARNINGS 1
//稀疏矩阵的十字链表表示
#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 4
#define Max 4
typedef int ElemType;
typedef struct mtxn
{
	int row;
	int col;
	struct mtxn* right, * down;
	union {
		ElemType value;
		struct mtxn* link;
	}tag;
}MatNode;
void CreateMat(MatNode* mh, ElemType a[][N])
{
	MatNode* h[Max];
	mh->row = M; mh->col = N;
	MatNode* r = mh;
	for (int i = 0; i < Max; i++)
	{
		h[i] = (MatNode*)malloc(sizeof(MatNode));
		h[i]->down = h[i]->right = h[i];
		r->tag.link = h[i];
		r = h[i];
	}
	r->tag.link = mh;
	for(int i =0;i<M;i++)
		for (int j = 0; j < N; j++)
		{
			if (a[i][j] != 0)
			{
				MatNode* p = (MatNode*)malloc(sizeof(MatNode));
				p->row = i; p->col = j; p->tag.value = a[i][j];
				MatNode* q = h[i];
				while(q->right != h[i] && q->right->col < j) q = q->right;
				p->right = q->right; q->right = p;
				q = h[j];
				while (q->down != h[j] && q->down->row < i) q = q->down;
				p->down = q->down; q->down = p;
			}
		}
}
void DispMat(MatNode* mh)		//输出十字链表
{
	MatNode* p, * q;
	printf("行=%d  列=%d\n", mh->row, mh->col);
	p = mh->tag.link;
	while (p != mh)
	{
		q = p->right;
		while (p != q) 		//输出一行非零元素
		{
			printf("%d\t%d\t%d\n", q->row, q->col, q->tag.value);
			q = q->right;
		}
		p = p->tag.link;
	}
}
void DestroyMat(MatNode* mh)
{
	MatNode* pre, * p, * mp;
	mp = mh->tag.link;
	while (mp != mh)
	{
		pre = mp->right;
		while (pre != mp)
		{
			p = pre->right;
			free(pre);
			pre = p;
		}
		mp = mp->tag.link;
	}
	pre = mh->tag.link;
	while (pre != mh)
	{
		p = pre->tag.link;
		free(pre);
		pre = p;
	}
	free(mh);
}
int main()
{
	ElemType a[M][N] = { {1,0,0,2},{0,0,3,0},{0,0,0,4} };
	MatNode* t = (MatNode*)malloc(sizeof(MatNode));
	CreateMat(t,a);
	DispMat(t);
	DestroyMat(t);
	return 0;
}

运行结果如下:

😃😃😃😃😃

总结:我们可以看到稀疏矩阵的十字链表是三元组的改进,运用这两种方法可以很好的解决稀疏矩阵的存储问题,从而节省空间,至于这两种要选择哪一个要看具体情况和自身对那个比较熟练。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/312811.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

超简单的简历模板精选5篇

HR浏览一份简历也就25秒左右&#xff0c;如果你连「好简历」都没有&#xff0c;怎么能找到好工作呢&#xff1f; 如果你不懂得如何在简历上展示自己&#xff0c;或者觉得怎么改简历都不出彩&#xff0c;那请你一定仔细读完。 个人求职简历第 1 篇 男 22 本科 AI简历 市场营…

Open CV 图像处理基础:(五)Java 使用 Open CV 的绘图函数

Java 使用 Open CV 的绘图函数 使用 Open CV 在 Java 中对图片使用绘图函数&#xff0c;分别绘制矩形、斜线、圆形、椭圆形以及添加文本 Java 使用 Open CV 的绘图函数 Java 使用 Open CV 的绘图函数函数绘制矩形绘制线绘制圆形绘制椭圆添加文本 代码示例Open CV 专栏导航 函…

redis stream restTemplate消息监听队列框架搭建

整体思路 1. pom增加redis依赖&#xff1b; 2. 消息监听器&#xff0c;实现StreamListener接口&#xff0c;处理消息到达逻辑&#xff1b; 3. 将消息订阅bean及监听器注册到配置中&#xff1b; 1. pom <?xml version"1.0" encoding"UTF-8"?> <…

vue的mvvm模式

1.mvvm优点&#xff1a; 低耦合&#xff1a;视图&#xff08;View&#xff09;可以独立于Model变化和修改&#xff0c;一个ViewModel可以绑定到不同的View上&#xff0c;当View变化的时候Model可以不变&#xff0c;当Model变化的时候&#xff0c;View也可以不变。 可复用&…

PostgreSQL 配置文件、数据储存目录

文章目录 查询配置文件所在位置查询数据储存目录PostgreSQL的数据目录 查询配置文件所在位置 show config_file; -- 查询配置文件所在位置查询数据储存目录 show data_directory; -- 查询数据储存目录PostgreSQL的数据目录 在PostgreSQL的数据目录&#xff08;C:\Program…

android studio使用总结

gradle是项目构建的工具&#xff0c;在gradle-wrapper.properties这个文件中设置&#xff0c; 然后就会下载相应版本的安装包到这个路径C:\Users\ly.gradle\wrapper\dists&#xff0c;例如这里是7.0.2&#xff0c; gradle和studio中的jdk版本需要对应&#xff0c;否则无法构建项…

使用numpy处理图片——图片拼接

大纲 左右拼接上下拼接 在《使用numpy处理图片——图片切割》一文中&#xff0c;我们介绍了如何使用numpy将一张图片切割成4部分。本文我们将反其道而行之&#xff0c;将4张图片拼接成1张图片。 基本的思路就是先用两张图以左右结构拼接成上部&#xff0c;另外两张图也以左右拼…

实现用户注册功能

实现用户注册功能 注&#xff1a;打赏即可获得一对一线下辅导&#xff0c;机不可失&#xff0c;时不再来

软件系统培训方案(Word)

1. 培训概述 2. 培训目的 3. 培训对象及要求 3.1. 培训对象 3.2. 培训人员基本要求 4. 培训方式 5. 培训内容 6. 培训讲师 7. 培训教材 8. 培训质量保证 8.1. 用户培训确认报告 8.2. 培训疑问解答 软件开发全文档下载&#xff1a;软件项目开发全套文档下载_软件项目文档-CSDN博…

MySQL——SQL语句进阶

select * from 表 where 条件 group by 条件 order by 排序 limit 分组 Group by select * from 表 group by 条件 结果为每个分组的第一条记录&#xff0c;该条记录作为该组的标志 select * from subject GROUP BY gradeidselect count(1),gradeid from subject GROUP B…

vue3+ts+vite项目从0 搭建,配置安装router/pinia/element-plus/scss等

一、安装vite环境 官网&#xff1a;https://cn.vitejs.dev/guide/why.html npm init vite1.选择vue 2.选择typescipt 3.创建成功 默认项目结构如下 4.安装项目依赖 npm install 5.启动项目 npm run dev二。安装配置scss 1.运行安装scss npm install -D sass sass-loa…

[UI5] ODATA V4中的CRUD

文章目录 前言一、Read二、Create三、Update四、Delete 前言 ODATA V4在CRUD方面与V2截然不同。 这篇文章简单介绍V4中是如何进行CRUD操作 一、Read Model不再有read方法&#xff0c; 一般是把Path绑定到View中进行读取&#xff0c; 如果需要额外的读取数据&#xff0c;可使用…

Vant-ui图片懒加载

核心代码 在你的全局顶部引入和初始化 Vue.use(vant.Lazyload, {loading: /StaticFile/img/jiazai.jpg,error: /StaticFile/img/jiazai.jpg,lazyComponent: false, });//图片懒加载 <img v-lazy"https://img-blog.csdnimg.cn/direct/3d2c8a7e2c0040488a8128c3e381d58…

ubuntu20.04 deepstream 6.3安装

1.基础环境gstreamer sudo apt install \ libssl-dev \ libgstreamer1.0-0 \ gstreamer1.0-tools \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly \ gstreamer1.0-libav \ libgstreamer-plugins-base1.0-dev \ libgstrtspserver-1.0-0 …

基于JavaWeb+BS架构+SpringBoot+Vue+Hadoop短视频流量数据分析与可视化系统的设计和实现

基于JavaWebBS架构SpringBootVueHadoop短视频流量数据分析与可视化系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 目  录 目  录 I 1绪 论 1 1.1开发背景 1 1.2开…

IDEA创建springboot+mybatis项目(java8 和java21可行)

IDEA创建springbootmybatis项目&#xff08;java8 和java21可行&#xff09; 今天博主讲一下&#xff0c;IDEA创建springbootmybatis项目的文章。 步骤分别是如下几步&#xff1a; 1. 创建maven项目 2. 配置pom.xml文件 3. 创建目录结构 4. 创建配置项目文件 5. 生成创建…

【pytorch】使用pytorch构建线性回归模型-了解计算图和自动梯度

使用pytorch构建线性回归模型 线性方程的一般形式 衡量线性损失的一般形式-均方误差 pytorch中计算图的作用和优势 在 PyTorch 中&#xff0c;计算图&#xff08;Computational Graph&#xff09;是一种用于表示神经网络运算的数据结构。每个节点代表一个操作&#xff0c;例如…

报错:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver

记一次关于驱动报错的问题 背景 原始驱动版本515&#xff0c;cuda 11.5.。 要将cuda 版本升级到11.7 内容 我去nvidia官网下载了 11.7.1的cuda tools nvidia CUDA 下载。 按照步骤安装后&#xff0c;执行nvcc -V ,可以看到已经正常更新 但是执行 nvidia-smi 时报错 NVIDIA…

67.网游逆向分析与插件开发-角色数据的获取-分析角色数据基址

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;角色类的数据分析与C还原-CSDN博客 基址这个东西说好找也好找&#xff0c;说不好找是真找不着&#xff0c;但就根据一个原则&#xff0c;就是确认这个东西有基址还是没基址&#xff0c;为什么会有没基…

专搞大厂?免费开源?这个小工具我相信很多人需要!

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; XHS-Downloader v1.6是一款功能齐全的免费开源工具&#xff0c;它使用Python Requests库开发而成&#xff0c;用于采集和下载X红S作品。该工具具备多…