数组以及稀疏矩阵的快速转置算法详细分析

一.数组:

1.数组的地址计算:

数组的地址计算比较简单,读者可以自行了解,在这里不再赘述;

2.特殊矩阵的压缩存储:

 在这里我们主要说明稀疏矩阵的主要内容:

(1)稀疏矩阵的三元组表示法:

在这里,存放非零元素的行标,列标以及元素值:

三元组表存放在一维数组中,一行一行存储,并且在每一行中,按照列号递增的方式来 !

(2)稀疏矩阵的三元组表的定义:

#define MAXSIZE 1000#define ElementType int
typedef struct
{int row, col;//定义行标,列标ElementType e;
}Triple;typedef struct//定义矩阵
{Triple data[MAXSIZE];int m, n, len;//矩阵的行,列数,以及非零元素的个数;
}TSmatrix;

 (3)矩阵的转置算法

a.经典的矩阵转置:
//经典的矩阵转置算法:就是给出矩阵及其转置矩阵,对应位置直接赋值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];}}
}
b.用三元组实现稀疏矩阵的转置:

关键点:保证转置之后的三元组也是按照行序优先来进行存储的

那么如果说先直接交换行列的值,那么就会造成转换之后的顺序紊乱,如果要保证转置之后仍然按照行优先来进行存储,那么我们需要对其按照行优先进行排序,就会移动大量的元素;

为了解决上述问题:

(1)列序递增转置算法

假设A为要转置的三元组表,B为最终结果的存放;

列序递增即按照A的列号进行递增排列存储的算法;

依次扫描A的列,每一个分别找出列号为1-K的,找到后就存入B中;

在这里:可能会有读者有这样的疑问:我们已经按照A的列号进行递增存贮,我们是否还需要对A的行号进行比较判断呢?以保证转置之后的的元素按照“列序”递增的顺序进行排列

答案是否定的,在转置之前,A就是按照行号递增来进行排序的,那么我们一定是先找到行号比较小的符合条件的元素,所以不需要再对行号进行排序;

//稀疏矩阵的列序递增转置算法void TransposeTSMatrix(TSmatrix A, TSmatrix* B)//B传址调用
{int i, j, k;//先对B的行列数,以及元素个数进行初始化B->m = A.n;B->n = A.m;B->len = A.len;if (B->len > 0){j = 0;for (k = 1; k <= A.n; k++)//扫描A,找到列数等于K的元素{for (i = 1; 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.len最大为A.m*A.n,此时算法时间复杂度为:O(A.m*A.n^2),而经典的算法实现转置的时间复杂度为:O(A.m*A.n)

由此可见:采用列序递增的算法,储存空间减少,但是在非零元素的个数较多时,时间复杂度并未显著降低;

(2)一次定位快速转置算法

一次定位快速转置:为了降低上述过程的时间复杂度;

那么我们需要以牺牲空间为代价:引入num[],和position[]这两个数组

其中num[]用于存放每一列的非零元素的总个数,position数组用于存放每一列的第一个非零元素对应在B中应该存放的位置,即在B三元组中的下标;

num[col]:扫描一遍三元组表A,A的元素的列标出现一次,num[col]就增加1,最终得到相应的列标对应的总的非零元素的个数;

position[col]:根据上述position其实就是表示对应元素在B中应该存放的下标的值;那么position[col]=position[col-1]+num[col-1],即上一列的下标,加上上一列的总的元素所占的位置,就是这一列的首非零元的在B中的下标;

在算法实现中:我们首先将num初始化为0,并且遍历一次A,求出相应的num数组;

其次我们应该利用:position[col]=position[col-1]+num[col-1],这个语句来计算列对应的position的值,并且由于存在col-1,而col是从1开始的,而第一个存储的元素的在B中的下标一定为1,那么我们可以直接将position[1]=1即可;然后就可以从A的列标为2,开始遍历,计算position[col];在这里是给position赋值,所以不用初始化为0;

关于B中的对应的下标的移动:在不同的列中,是通过position来进行增加移动的;

那在相同的列中呢?我们可以在相同的列中,每存储到B中一个元素,就把对应的列position[col]++,然后就可以使得position[col]一直都指向即将要存储的正确位置了;

最后,再次遍历A,将A的行列以及元素值都赋给B,每赋一个,就把对应的position[col]++,更新位置即可!(只要能够理解num和position的实现,就能够理解快速转置算法啦!

以下是具体的代码实现:

void FastTransposeTSMatrix(TSmatrix A, TSmatrix *B)
{int col, t, p, q;//列标int num[MAXSIZE], position[MAXSIZE];//仍然是先初始化B的行列数以及非零元素值B->len = A.len;B->n = A.m;B->m = A.n;if (B->len > 0){for (col = 1;col <= A.n; col++){num[col] = 0;//先将num数组初始化为0;//且数组是从1开始的!}//接着遍历A中的所有元素for (t = 1; t < A.len; t++){num[A.data[t].col]++;//A中的元素的列标作为num的下标;}position[1] = 1;//第一个肯定是存储在第一个位置//那么从第二列开始赋值;for (col = 2; col <= A.n; col++){position[col] = position[col - 1] + num[col - 1];}for (p = 1; p <= A.len; p++){col = A.data[p].col;//列数取决于A中的元素的列数q = position[col];//q一直是在B中的下标;B->data[q].row = A.data[p].col;//B的行等于A的列;B->data[q].col = A.data[p].row;B->data[q].e = A.data[p].e;position[col]++;//下一个元素依然可能是这个列,因此改变下标位置;而不是这个列,对应的也有新的position值,所以....}}
}

一次定位快速转置的时间复杂度:在这里时间主要耗费在4个并列的单循环上;分别为:O(A.len)+O(A.n)+O(A.len)+O(A.n),那么该算法的时间复杂度就为:O(A.n+A.len)

那么我们总结一下:按照列序递增的方式与一次定位的区别:

按照列序递增,遍历K次A,按照列号递增,每次找到对应的列号的运算,再存入到B中,也就是必须是依次存放,列号要么相等,要么相邻;

而对于一次定位快速转置来说:遍历一次,不用非要是挨着的或者是一样的列标一次存入,按照列标存入到对应的应该存放的位置,不一定非要连续存入,其实更像是插入;一次定位的关键也就在这,就是要找到列标对应的正确的存放位置,也就是上述所说的position[col]的计算;


以上就是关于稀疏矩阵快速转置的算法理解,欢迎大家在评论区进行交流!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

J垃圾回收

J垃圾回收 1 概述2 方法区的回收3 如何判断对象可以回收3.1 引用计数法3.2 可达性分析法 4 常见的引用对象4.1 软引用4.2 弱引用4.3 虚引用4.4 终结器引用 5 垃圾回收算法5.1 垃圾回收算法的历史和分类5.2 垃圾回收算法的评价标准5.3 标记清除算法5.4 复制算法5.5 标记整理算法…

sky08、09笔记常用组合逻辑电路

本节的目的是为了更好的预估delay。 1.1bit全加器 module fadd_1b( a, b, cin, s, cout ); input wire a,b,cin; output wire s,cout;wire p,g; assign p a|b;//propagate carry assign g a&b;//generate carry assign s a^b^cin; assign cout (p&cin)|g; endmodu…

使用Python脚本检测服务器信息并定时发送至管理员邮箱

在日常的系统管理工作中&#xff0c;监测服务器的资源占用情况至关重要&#xff0c;我们需要及时获得通知以便采取相应措施。我新装了一台UbuntuServer服务器&#xff0c;写了一个可以定期收集服务器的CPU、内存、网络和磁盘信息&#xff0c;并通过邮件将这些信息发送给管理员的…

github上的软件许可证是什么?如何合并本地的分支德语难学还是俄语更加难学?站在一个中国人的立场上,德语难学还是俄语更加难学?俄语跟德语有什么样的显著差别?

目录 github上的软件许可证是什么&#xff1f; 如何合并本地的分支 德语难学还是俄语更加难学&#xff1f; 站在一个中国人的立场上&#xff0c;德语难学还是俄语更加难学&#xff1f; 俄语跟德语有什么样的显著差别&#xff1f; github上的软件许可证是什么&#xff1f; …

经典问题解答(顺序表)

问题一&#xff1a;移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不…

信号处理相关知识

1.序列 2.数字信号的自变量一定是整数&#xff0c;幅度上取值是有限的状态&#xff08;不一定是整数&#xff09;。 3.抽取和插值

【Java开发指南 | 第一篇】类、对象基础概念及Java特征

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 类、对象基础概念Java特征 Java 是一种面向对象的编程语言&#xff0c;它主要通过类和对象来组织和管理代码。 类、对象基础概念 类&#xff1a;类是一个模板&#xff0c;它描述一类对象的行为和状态。例如水…

[BT]BUUCTF刷题第17天(4.15)

第17天&#xff08;共3题&#xff09; Web [强网杯 2019]高明的黑客 .tar.gz 是 Linux 系统下的压缩包&#xff0c;访问即可下载 打开后有3000多个php文件&#xff0c;通过题解得知需要写Python脚本找出合适的GetShell文件&#xff08;因为每个文件里都会通过system函数执行…

【笔试训练】day2

文章目录 1.牛牛的快递代码&#xff1a; 2.最小花费爬楼梯思路&#xff1a;代码&#xff1a; 3.数组中两个字符串的最小距离思路&#xff1a;代码&#xff1a; 1.牛牛的快递 注意一个坑&#xff0c;首先就是加急是总共加5块&#xff0c;不是每千克加5块。 思路呃&#xff0c;没…

安卓apk文件签名

一、环境准备 链接: https://pan.baidu.com/s/1D3WxIL5M5ewyFNTqJzARPw 提取码: pd6w 上篇博文编译的apk文件 1、docker build -t android-build:v1.0.1 . 直接制作镜像 2、docker run -it android-build:v1.0.1 /bin/bash 运行进入容器 指定sdk的路径&#xff0c;然后直接…

计算机网络3——数据链路层1

文章目录 一、介绍1、基础2、内容 二、数据链路层的几个共同问题1、数据链路和帧2、三个基本问题1&#xff09;封装成帧2&#xff09;透明传输3&#xff09;差错检测 三、点对点协议 PPP1、PPP协议的特点1&#xff09;PPP 协议应满足的需求2&#xff09;PPP 协议的组成 2、PPP协…

JS-32-jQuery01-jQuery的引入

一、初识jQuery jQuery是JavaScript世界中使用最广泛的一个库。鉴于它如此流行&#xff0c;又如此好用&#xff0c;所以每一个入门JavaScript的前端工程师都应该了解和学习它。 jQuery是一个优秀的JS函数库。 &#xff08;对BOM和DOM的封装&#xff09; jQuery这么流行&#x…

Leetcode二叉树刷题

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true public boolean isSymmetric(TreeNode root) {if(rootnull)return true;return compare(root.left,root.right);}public boole…

Emacs之增加/取消输入括号自动匹配(一百三十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【测试开发学习历程】python常用的模块(中)

目录 5 time模块 5.1、Python中的四种格式的时间&#xff1a; 5.2、time模块中的常用函数 6 I/O流操作 6.1 创建文件 6.2 读取一个文件存入到另外一个文件 6.3 with open as 结构 6.4 open和with open as的区别 7 Excel的操作模块-openpyxl 7.1、新建Excel文件进行读…

读天才与算法:人脑与AI的数学思维笔记01_洛夫莱斯测试

1. 创造力 1.1. 创造力是一种原动力&#xff0c;它驱使人们产生新的、令人惊讶的、有价值的想法&#xff0c;并积极地将这些想法付诸实践 1.2. 创造出在表面上看似新的东西相对容易 1.3. 在遇到偶然间的创造性行为时&#xff0c;都会表现得异…

Vitis HLS 学习笔记--ap_int.h / ap_fixed.h(2)-深度探究

目录 1. 前文回顾 1.1 简单背后的复杂 1.2 复杂性的来源 2. 关键代码 2.1 功能概述 2.2 关系梳理 2.3 理解构造函数二 2.4 理解HLS_CONSTEXPR 2.5 理解const volatile 3. 探究ap_int<8> c&#xff1b;经历了什么 4. 在调试中查看 1. 前文回顾 在《Vitis HLS…

使用 npm 工具高效更新项目依赖包

团队内部会用工具定时检查包的最新版本并通知&#xff0c;以便我们及时跟进社区进展&#xff0c;避免和技术栈出现版本脱节导致无法使用最新特性和优化内容 这里只说明手动查看和更新包的主要几个命令。 npm outdated&#xff1a;检查项目中过时的依赖包及其最新版本。 npm i…

基于Canvas实现的简历编辑器

基于Canvas实现的简历编辑器 大概一个月前&#xff0c;我发现社区老是给我推荐Canvas相关的内容&#xff0c;比如很多 小游戏、流程图编辑器、图片编辑器 等等各种各样的项目&#xff0c;不知道是不是因为我某一天点击了相关内容触发了推荐机制&#xff0c;还是因为现在Canvas…

计算机网络 Cisco路由器基本配置

一、实验内容 1、按照下表配置好PC机IP地址和路由器端口IP地址 2、配置好路由器特权密文密码“abcd&#xff0b;两位班内序号”和远程登录密码“star” 3、验证测试 a.验证各个接口的IP地址是否正确配置和开启 b.PC1 和 PC2 互ping c.验证PC1通过远程登陆到路由器上&#…