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

稀疏矩阵的三元组表表示法及其转置

1. 什么是稀疏矩阵

稀疏矩阵是指矩阵中大多数元素为零的矩阵。

从直观上讲,当元素个数低于总元素的30%时,这样的矩阵被称为稀疏矩阵。

由于该种矩阵的特点,我们在存储这种矩阵时,如果直接采用二维数组,就会十分浪费空间,因为其中大多数元素都是重复的零。

稀疏矩阵的三元组表表示法

对于稀疏矩阵的压缩存储,采用只存储非零元素的方法。

由于稀疏矩阵中非零元素a_{ij}的分布没有规律,因此在存储非零元素值得同时,还必须存储该非零元素在矩阵中的位置信息,即行号和列号。

也就是采用三元组的结构存储:

为处理方便,将稀疏矩阵中非零元素对应的三元组行号依次增大进行存放。

这也就解释了,为什么稀疏矩阵是非零元素占比小于30%的矩阵。

因为采取三元组的结构储存,一个元素会占用三个单元的空间,只有当零元素占比小于30%时,这种存储结构才能在空间上有较明显的收益。

稀疏矩阵三元组表的类型定义

#define ElementType int//一个三元组元素
typedef struct 
{int row, col;//非零元素行下标和列下标ElementType e;
}Triple;//稀疏矩阵
typedef struct 
{Triple* data;//非零元素的三元组表int m, n, len;//矩阵行数,列数,非零元素个数int capacity;//容量
}TSMatrix;

 2. 对稀疏矩阵进行基本操作

//初始化稀疏矩阵
void TSMInite(TSMatrix* ps)
{assert(ps);ps->data = NULL;ps->m = TSM_ROWMAX;ps->n = TSM_COLMAX;ps->len = 0;ps->capacity = 0;
}//销毁稀疏矩阵
void TSMDestroy(TSMatrix* ps)
{assert(ps);free(ps->data);ps->data = NULL;ps->len = 0;ps->capacity = 0;
}//检查扩容
void CheckCapacity(TSMatrix* ps)
{assert(ps);if(ps->capacity == ps->len){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;Triple* tmp = (Triple*)realloc(ps->data, newcapacity * sizeof(Triple));if(tmp == NULL){perror("realloc");exit(-1);}ps->data = tmp;ps->capacity = newcapacity;}
}//插入元素
void ElemInsert(TSMatrix* ps, Triple x)
{assert(ps);CheckCapacity(ps);if(ps->len == 0){ps->data[ps->len] = x;}if(x.row < ps->data[0].row){for(int j = ps->len; j > 0; j--){ps->data[j] = ps->data[j - 1];}ps->data[0] = x;}elsefor(int i = 0; i < ps->len; i++){if(x.row >= ps->data[i].row&&x.row <= ps->data[i + 1].row||i == ps->len - 1){for(int j = ps->len; j > i + 1; j--){ps->data[j] = ps->data[j - 1];}ps->data[i + 1] = x;break;}}ps->len++;
}//打印元素
void TSMPrint(TSMatrix ps)
{for(int i = 0; i < ps.len; i++){printf("row = %d col = %d e = %d\n", ps.data[i].row, ps.data[i].col, ps.data[i].e);}printf("\n");
}

这些函数基本是以顺序表操作函数为蓝本写的,目的是为了方便我们实现稀疏矩阵的转置。

只不过插入元素的函数需要确保插入之后,三元组的行号是依次递增的。

3. 稀疏矩阵的转置

需要强调的是,矩阵的常规存储是二维的,而三元组表存储是一维的,由于矩阵存储结构的变化,也带来了运算方法的不同,必须认真分析。

3.1 稀疏矩阵转置的经典算法

void TransMatrix(ElementType source[m][n], ElementType dest[n][m])
{int i, j;for(i = 0; i < m; i++)for(j = 0; j < n; j++)dest[j][i] = source[i][j];
}

这个算法是针对传统的二维数组的存储方式。

3.2 用三元组表实现稀疏矩阵的转置

假设A和B是稀疏矩阵source和dest的三元组表,则实现转置的简单方法如下:

1. 三元组表A的行,列互换就可以得到B中的元素。

2. 转置后的矩阵的三元组表B中的三元组不是以“行序为主序”存储的,为保证三元组表B也是以“行序为主序”进行存放的,则需要对该三元组表B按行下标(即A的列下标)以递增顺序重新排列。

 上图中的步骤很容易实现,但是重新排序势必会大量移动元素,从而影响算法的效率。

为避免上述简单转置算法中重新排序引起的元素移动,可采取接下来的两种处理方法。

3.2.1 列序递增转置法

算法思想

这里的列序指的是A的列,也就是按照A的列序来将元素转置到B中。

即将A的第一列全部转置到B中(得到B的第一行)后,再将A的第二列全部转置到B中,以此类推。

代码

//列序递增转置法
void TSMSwitch1(TSMatrix A, TSMatrix* B)
{assert(B);TSMDestroy(B);B->data = (Triple*)malloc(A.capacity * sizeof(Triple));B->capacity = A.capacity;B->len = A.len;B->m = A.n;B->n = A.m;int j = 0;//记录B当前空位for(int k = 0; k < A.n; k++){for(int i = 0; i < A.len; i++){if(A.data[i].col == k){B->data[j].row = A.data[i].col;B->data[j].col = A.data[i].row;B->data[j].e = A.data[i].e;j++;}}}
}

分析

这种算法确实使得我们不用再单独进行排序,但是双重循环依然造成了较高的时间复杂度(O(A.n * A.len))。

那么我们能否降低该算法的时间复杂度呢?

如果能,那么我们的着手点一定是想办法优化掉二重循环。

可以发现,该算法中二重循环出现的原因在于,必须将A的第一列全部转置之后才能转置第二列,每列转置需要重新扫描一次A。

那么,我们有没有办法使得各列同时进行存放呢,这样就只用扫描一次A了。

3.2.2 一次定位快速转置法

算法思想

如果我们知道A的每一列有多少个元素,那么就可以推知B中每一行的起始位置。

这样一来,假如某次在A中扫描到第n列的元素,我们就可以直接将其放到B中的第n行所在位置,而不用先放完一列再放下一列。

所以,我们准备进行三次循环:

1. 定义数组num,数组的下标表示A的列,遍历A并将每一列元素的个数记录在num中。

2. 定义数组position,数组下标表示B的行,遍历position,根据A每一列元素的个数得到对应行的起始位置。

3. 遍历A,根据position数组,将A中的元素转置到B的对应行。

代码 

//一次定位快速转置算法
void TSMSwitch2(TSMatrix A, TSMatrix* B)
{assert(B);TSMDestroy(B);B->data = (Triple*)malloc(A.capacity * sizeof(Triple));B->capacity = A.capacity;B->len = A.len;B->m = A.n;B->n = A.m;int num[B->m];int position[B->m];memset(num, 0, B->m * sizeof(int));memset(num, 0, B->m * sizeof(int));for(int i = 0; i < A.len; i++){num[A.data[i].col]++;}position[0] = 0;for(int row = 1; row < B->m; row++){position[row] = position[row - 1] + num[row - 1];}for(int i = 0; i < A.len; i++){B->data[position[A.data[i].col]].row = A.data[i].col;B->data[position[A.data[i].col]].col = A.data[i].row;B->data[position[A.data[i].col]].e = A.data[i].e;position[A.data[i].col]++;}
}

算法分析

显然,一次定位快速转置算法的时间效率要高得多,它在时间性能上由于列序递增转置法,但在空间耗费上增加了两个辅助向量空间,即num和position。

由此可见,算法在时间上的节省是以更多的储存空间为代价的。

相关文章:

稀疏矩阵的三元组表表示法及其转置

1. 什么是稀疏矩阵 稀疏矩阵是指矩阵中大多数元素为零的矩阵。 从直观上讲&#xff0c;当元素个数低于总元素的30%时&#xff0c;这样的矩阵被称为稀疏矩阵。 由于该种矩阵的特点&#xff0c;我们在存储这种矩阵时&#xff0c;如果直接采用二维数组&#xff0c;就会十分浪费…...

docker安装rabbitMQ,并且创建账号

# 创建docker容器启动,挂到后台运行 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management # 打开防火墙 sudo firewall-cmd --zonepublic --add-port5672/tcp --permanent sudo firewall-cmd --zonepublic --add-port15672/tcp --permanent s…...

wireshark解析grpc/protobuf的方法

1&#xff0c;wireshark需要安装3.20以上 下载地址&#xff1a;https://www.wireshark.org/ 2&#xff0c;如果版本不对&#xff0c;需要卸载&#xff0c;卸载方法&#xff1a; sudo rm -rf /Applications/Wireshark.app sudo rm -rf $HOME/.config/wireshark sudo rm -rf /…...

软件测试用例(2)

具体的设计方法 -- 黑盒测试 因果图 因果图是一种简化的逻辑图, 能直观地表明程序的输入条件(原因)和输出动作(结果)之间的相互关系. 因果图法是借助图形来设计测试用例的一种系统方法, 特别适用于被测试程序具有多种输入条件, 程序的输出又依赖于输入条件的各种情况. 因果图…...

集群式无人机仿真环境和数据集

仿真环境和数据集 Quick StartAcknowledgementsSwarmSim Quick Start Compiling tests passed on 20.04 with ros installed. You can just execute the following commands one by one. # Download the Simulator and run it wget https://cloud.tsinghua.edu.cn/library/34…...

IPSec VPN

IP Security,IP安全 1、特点 L3的VPN 缺:不支持组播、配置复杂、延迟增加、资源消耗较多 优:具备访问控制、密码学四个维度、抗重放打击 2、组件 ①安全协议 1)验证头技术(AH) IP协议号51 提供数据完整性检查,身份验证,抗重放攻击 无法做数据的机密性 AH的完…...

docker部署nacos,单例模式(standalone),使用内置的derby数据库,简易安装

文章目录 前言安装创建文件夹docker指令安装docker指令安装-瘦身版 制作docker-compose.yaml文件查看页面 前言 nacos作为主流的服务发现中心和配置中心&#xff0c;广泛应用于springcloud框架中&#xff0c;现在就让我们一起简易的部署一个单例模式的nacos&#xff0c;版本可…...

systemd监听服务配置文件更新自动重启服务

背景&需求 需要频繁更改一个服务的配置文件进行测试 实现 配置服务的systemd文件 vim /lib/systemd/system/xxx.service [Unit] Descriptionxxx daemon, A rule-based proxy in Go.[Service] Typesimple ExecStart/opt/xxx/xxx-d /etc/xxx/ Restartalways[Install] Wan…...

【yy讲解PostCSS是如何安装和使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

YOLO电动车检测识别数据集:12617张图像,yolo标注完整

YOLO电动车检测识别数据集&#xff1a;12617张图像&#xff0c;电动车一类&#xff0c;yolo标注完整&#xff0c;部分图像应用增强。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 需要此数据集或其他任何数据集请私信...

从汇编看函数调用

文章目录 函数调用流程栈相关寄存器及的作用简介寄存器功能指令功能 栈函数的括号{}正括号反括号 参数传递传值&#xff0c;变量不可改传指针&#xff0c;变量可改C 传引用 函数调用实例 函数调用流程 目标&#xff1a;函数调用前后栈保持不变 保存main函数的寄存器上下文移…...

node.js的错误处理

当我打开一个不存在的文件时&#xff0c;错误如下&#xff1a; 在读取文件里面写入console.log&#xff08;err&#xff09;&#xff0c;在控制台中可以看到我的错误代码类型&#xff1a;文件不存在的错误代码 ENOENT。见更多错误代码---打开node.js官方API文档Error 错误 | N…...

shell的编写

文章目录 1.框架2.命令行3.获取用户命令字符串4.命令行字符串分割5.执行命令和内建命令6.完整代码&#xff1a; 1.框架 我们知道shell是一直存在的&#xff0c;所以首先我们第一步就是要搭建一个框架&#xff0c;使其一直存在。 那么也很简单&#xff0c;一个while循环就可以完…...

css心跳动画

图标引入 <img class"icon" src"heart.svg" alt"" srcset""> CSS代码 <style>.icon {animation:bpm 1s linear,pulse 0.75s 1s linear infinite;}keyframes pulse {from,75%,to {transform: scale(1);}25% {transform:…...

在 Amazon Timestream 上通过时序数据机器学习进行预测分析

由于不断变化的需求和现代化基础设施的动态性质&#xff0c;为大型应用程序规划容量可能会非常困难。例如&#xff0c;传统的反应式方法依赖于某些 DevOps 指标&#xff08;如 CPU 和内存&#xff09;的静态阈值&#xff0c;而这些指标在这样的环境中并不足以解决问题。在这篇文…...

【智能排班系统】快速消费线程池

文章目录 线程池介绍线程池核心参数核心线程数&#xff08;Core Pool Size&#xff09;最大线程数&#xff08;Maximum Pool Size&#xff09;队列&#xff08;Queue&#xff09;线程空闲超时时间&#xff08;KeepAliveTime&#xff09;拒绝策略&#xff08;RejectedExecutionH…...

C语言——内存函数

前言&#xff1a; C语言中除了字符串函数和字符函数外&#xff0c;还有一些函数可以直接对内存进行操作&#xff0c;这些函数被称为内存函数&#xff0c;这些函数与字符串函数都属于<string.h>这个头文件中。 一.memcpy&#xff08;&#xff09;函数 memcpy是C语言中的…...

ideaSSM图书借阅管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 SSM 图书借阅管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码 和数据库&#xff0c;系统主…...

普联一面4.2面试记录

普联一面4.2面试记录 文章目录 普联一面4.2面试记录1.jdk和jre的区别2.java的容器有哪些3.list set map的区别4.get和post的区别5.哪个更安全6.java哪些集合类是线程安全的7.创建线程有哪几种方式8.线程的状态有哪几种9.线程的run和start的区别10.什么是java序列化11.redis的优…...

SQLite的架构(十一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite下一代查询规划器(十&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 介绍 本文档介绍SQLite库的架构。 这里的信息对那些想要了解或 修改SQLite的内部工作原理。 接口SQL 命令处理器虚拟机B-树…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...

加密通信 + 行为分析:运营商行业安全防御体系重构

在数字经济蓬勃发展的时代&#xff0c;运营商作为信息通信网络的核心枢纽&#xff0c;承载着海量用户数据与关键业务传输&#xff0c;其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级&#xff0c;传统安全防护体系逐渐暴露出局限性&a…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...