C++数组应用之特殊矩阵的压缩存储

特殊矩阵(对称矩阵)的压缩存储和解压缩 特殊矩阵(对称矩阵)的压缩存储和解压缩 参考书目:严蔚敏《数据结构》P95-96 一、背景 ​ 矩阵在工程计算中经常使用,对于一些特殊矩阵,比如对称矩阵,稀疏矩阵……有时为了节省空间,可以对这类矩阵进行压缩存储。这里只讨论对称矩阵,上(下)三角矩阵和对角矩阵,掌握对称矩阵其他就很容易了 二、压缩原则 ​ 为多个值相同的元素只分配一个存储空间,对零元素不分配空间。 三、对称矩阵的压缩 性质: 0<=i,j<=n-1(在 程序中 数组下标是从 0 开始的) 举例: 压缩:以行序为主序存 阅读详情
 矩阵:           
      矩阵是数值程序设计中经常用到的数学模型,它是由 m 行和 n 列的数值构成(m=n 时称为方阵)。在用高级语言编制的程序中,通常用二维数组表示矩阵,它使矩阵中的每个元素都可在二维数组中找到相对应的存储位置。然而在数值分析的计算中经常出现一些有下列特性的高阶矩阵,即矩阵中有很多值相同的元或零值元,为了节省存储空间,需要对它们进行"压缩存储",即不存或少存这些值相同的元或零值元。 
操作:       
       可以对矩阵作加、减、乘等运算。
存储压缩目标:
       节约存储空间
压缩的方法:
       零元不存储
       多个值相同的只存一个
压缩存储的对象:
       稀疏矩阵
       特殊矩阵
特殊矩阵:
 值相同元素或者零元素分布有一定规律的矩阵称为特殊矩阵 例:对称矩阵、 上(下)三角矩阵都是特殊矩阵
特殊矩阵压缩存储(以对称矩阵为例)
对称矩阵是满足下面条件的n 阶矩阵: aij= aji  1<= i,j<= n
k= 0   1    2     3   4     5    6                      n(n+1)/2-1     
对称矩阵元素可以只存储下三角部分,共需 n(n+1)/2 个单元的空间( 三角矩阵的存储方式类似) 
以一维数组sa[0..n(n+1)/2-1]作为n 阶对称矩阵A的存储结构A中任意一元素 aij与它的存储位置 sa[k] 之间关系:
 
k= 0   1    2     3   4     5    6                      n(n+1)/2-1  
例如:a42 在 sa[ ]中的存储位置是:
           k=4*(4+1)/2+2=12
           sa[12]= a42
 
带状矩阵所有非0元素都集中在以主对角线为中心的带状区域,半带宽为d时, 非0元素有
(2d+1)*n-(1+d)*d个(左上角与右下角补上0后,最后必须减掉),如下图怕示:
为计算方便,认为每一行都有2d+1个非0元素,若少则0补足存放矩阵的数组sa[ ]有:n(2d+1)个元素数组,元素sa[k]与矩阵元素aij 之间有关系:
  k=i*(2d+1)+d+(j-i)(第一项i*(2d+1)表示前i行一共有几个元素,d+(j-i)这一项是用来确定第i行中,第j列前有几个元素,以i=j时,这时j-i=0,这个作为“分水岭“,左右两边的元素分别加上偏移量d。)
本例:d=1
K= 0    1         2        3      4    5     6           7    8      9      10   11    12    13      14 
(a0前以及a14处放一个0是用来表示在矩阵的左上角及右下角补上的0)
稀疏矩阵:
行数m = 6, 列数n = 7, 非零元素个数t = 6
稀疏矩阵(SparseMatrix)的抽象数据类型
 
template <class Type>
 
class SparseMatrix {
      
int Rows, Cols, Terms;    //行/列/非零元素数
      Trituple<Type> smArray[MaxTerms]; 
 
public:                                 //三元组表
      SparseMatrix ( int MaxRow, int Maxcol ); 
      SparseMatrix
<Type> Transpose ( );   //转置
      SparseMatrix<Type>      //相加
               Add ( SparseMatrix<Type> b );
      SparseMatrix
<Type>      //相乘
            Multiply ( SparseMatrix<Type> b );
 }
 
 A的三元组顺序表图示
           
三元组 (Trituple) 类的定义
template<class Type> class SparseMatrix<Type>;
template
<class Type> 
 
class Trituple {   
 friend 
class SparseMatrix <Type>
 
private:
      
int row, col;       //非零元素所在行号/列号
      Type value;       //非零元素的值
 }
     
                      
稀疏矩阵
转置矩阵
用三元组表表示的稀疏矩阵及其转置:
           a.smArray                                    b.smArray
(a.Rows=6,a.Cols=7,a.Terms=8)            (b.Rows=7,b.Cols=6,b.Terms=8)
 
 
稀疏矩阵转置算法思想
对应上图的一个最简单的方法是把三元组表中的row与col的内容互换,然后再按照新的row中的行号对各三元组从小到大重新排序,最后得到上图右半部分的三元组表,但是用这样的方法其时间复杂度为平方级的,下面再用一种方法来处理:
假设稀疏矩阵A有n列,相应地,需要针对它的三元组表中的col列进行n次扫描,第k次扫描是在数组的col列中查找列号为k的三元组,若找到,则意味着这个三元组所表示的矩阵元素在稀疏矩阵的第k列,需要把它存放到转置矩阵的第k行。具体办法是:取出这个三元组,并交换其row(行号)与col(列号)的内容,连同value中存储的值,作为新三元组存放到矩阵的三元组表中。当n次扫描完成时,算法结束。程序清单如下:
稀疏矩阵的转置
template <class Type> SparseMatrix <Type> SparseMatrix <Type>:: Transpose ( ) {
//将稀疏矩阵a(*this指示)转置,结果在稀疏矩阵b中。
   SparseMatrix<Type> b ( Cols, Rows );//创建一个稀疏矩阵类的对象b
     b.Rows = Cols; b.Cols = Rows; //交换其row(行号)与col(列号)的内容,连同value
b.Terms = Terms;//中存储的值作为新三元组放到矩阵的三元组表中。
     if ( Terms > 0 ) { //非零元个数不为零                   
         int CurrentB = 0; //转置三元组表存放指针
for ( int k = 0; k < Cols; k++ )   //按列号做扫描,做cols次
         for ( int i = 0; i < Terms; i++ )        //在数组中找列号为k的三元组     
                 if ( smArray[i].col == k) { //第i个三元组中元素的列号为k           
                  b.smArray[CurrentB].row = k; //新三元组的行号
                  b.smArray[CurrentB].col=smArray[i].row;//新三元组的列号
                  b.smArray[CurrentB].value=smArray[i].value;//新三元组的值 
                 CurrentB++;                                              //存放指针加1                    
               }

     }

     
return 0;
 }

 若设稀疏矩阵的行数为Rows,列数为Cols,非零元素个数为Terms,则最坏情况下的时间复杂度主要取决于二重潜套for循环内的if语句,if语句在二重循环的作用下总的执行次数为O(Cols*Terms)。而在if控制内的赋值语句则执行了Terms次,它取决于三元组表本身的长度。若非零元素个数Terms与矩阵行,列数的乘积Rows*Cols等数量级,则上述程序清单的时间复杂度为O(Cols*Terms)=O(Rows*Cols*Cols)。设Rows=500,Cols=100,Terms=10000,则O(500*100*100)=O(5000 000),处理效率极低。
为了提高转置效率,采用一种快速转置的方法。在此方法中,引入两个辅助数组:
1. rowSize[]。用它存放事先统计出来的稀疏矩阵各列的非零元素个数,转置以后是转置矩阵各行的非零元素个数。具体做法是:先把这个数组清零,然后扫描矩阵A的三元组表,逐个取出三元组的列号col,把以此列号为下标的辅助数组元素的值累加1。
for(int i=0;i
 for(j=0;jrowSize[smArray[j].col]++;//统计,注意这里用到的简洁的算法
2. rowstart[]。用它存放事先计算出来的稀疏矩阵各行非零元素在转置矩阵的三元组表中应存放的位置。
rowSize[0]=0;//计算矩阵b第i行非零元素的开始存放位置
for(i=1;i
快速转置算法的思想
Ø         建立辅助数组 rowSize 和 rowStart,记录矩阵转置后各行非零元素个数和各行元素在转置三元组表中开始存放位置。
Ø         扫描矩阵三元组表,根据某项的列号,确定它转置后的行号,查 rowStart 表,按查到的位置直接将该项存入转置三元组表中。
Ø         转置时间代价为O(max(Terms, Cols))。若矩阵有200 列,10000个非零元素,总共需要10000次处理。
对应上图的代码在就像前面所列的:
 for ( int i = 0; i < Cols; i++ ) rowSize[i] = 0;  
 for ( i = 0; i < Terms; i++ )
       rowSize[smArray[i].col]++; 
 rowStart[0] = 0;                              
 for ( i = 1; i < Cols; i++ )                
       rowStart[i] = rowStart[i-1]+rowSize[i-1];
 
稀疏矩阵的快速转置
template <class Type> SparseMatrix<Type>
SparseMatrix
<Type>::FastTranspos ( ) {
//对稀疏矩阵a(*this指示)做快速转置,结果放在b中,时间代价为O(Terms+Columns)。
    int *rowSize = new int[Cols];//辅助数组,统计各列非零元素个数           
    int *rowStart = new int[Cols];//辅助数组,预计转置后各行存放位置                    
    SparseMatrix<Type> b ( Cols, Rows );//存放转置结果            
    b.Rows = Cols;   b.Cols = Rows;
   b.Terms 
= Terms;
    
if ( Terms > 0 ) {
        
for (int i = 0; i < Cols; i++) rowSize[i] = 0;//统计矩阵b中第i行非零元素个数
for ( i = 0; i < Terms; i++ )
//根据矩阵a中第i个非零元素的列号,将rowSize相当该列的计数加1
        rowSize[smArray[i].col]++; 
rowStart[
0] = 0;     //计算矩阵b第i行非零元素的开始存放位置
         for ( i = 1; i < Cols; i++ ) //rowStart[i]=矩阵b的第i行的开始存放位置          
           rowStart[i] = rowStart[i-1]+rowSize[i-1];
       
for ( i = 0; i < Terms; i++ ) {      //从a向b传送            
           int j = rowStart[smArray[i].col];//j为第i个非零元素在b中应存放的位置              
           b.smArray[j].row = smArray[i].col;
           b.smArray[j].col 
= smArray[i].row;
           b.smArray[j].value 
= smArray[i].value;
           rowStart[smArray[i].col]
++;         
       }

    }

    delete[ ] rowSize;   delete [ ] rowStart;
    
return b;
}

在此程序中有4个并列循环,其时间复杂度分别为O(Cols),O(Terms),O(Cols),和O(Terms),则程序总的时间复杂度为O(Cols+Terms)。当Terms与Rows*Cols等数量级时,程序的时间复杂度为O(Cols+Terms)=O(Rows*Cols)。设Rows=500,Cols=100,Terms=10000,则O(500*100)=O(50000)。当Terms远远小于Rows*Cols时,此程序会更省时间,但程序中需要增加两个体积为Cols的辅助数组。一般Terms总是大于Cols的,如果能够大幅度提高速度,这点空间存储上的开销是值得的。



7. 矩阵的快速转置算法 7. 矩阵的快速转置算法 成绩 10 开启时间 2014年11月1日 Saturday 08:00 折扣 0.8 折扣时间 2014年11月20日 Thursday 23:55 允许迟交 否 关闭时间 2014年11月23日 Sunday 23:55 矩阵的快速转置 阅读详情

相关推荐

PHP证书图片生成

$realname = "姓名"; $schoolname = "学校"; $idcard = "身份证号"; $image = imagecreatefrompng('certification.png'); // 证书模版图片文件的路径 $red = imagecolorallocate($image,00,00,00); // 字体颜色

4036

矩阵操作

稀疏矩阵 对称矩阵 三角矩阵

chpdirector84的专栏 1407

贝加莱Automation Studio 4.10安装保姆级教程:从官网下载到解决.Net 3.5报错

本文提供贝加莱Automation Studio 4.10的详细安装教程,涵盖从官网下载到解决.Net 3.5报错的全过程。特别针对工业自动化开发环境中常见的.Net Framework 3.5安装问题,提供多种经过验证的解决方案,包括控制面板安装、DISM命令离线安装和手动下载安装包等方法,帮助工程师顺利完成PLC开发环境的搭建。

weixin_30955617的博客 723

矩阵的压缩存储

若对一个n阶方阵A[1…n][1…n]中的任意一个元素aij都有aij=aji(1≤i,j≤n),则称其为对称矩阵。其中的元素可以划分为3个部分,即上三角区、主对角线和下三角区。在下三角矩阵中,上三角区的所有元素均为同一常量。其存储思想与对称矩阵类似,不同的是,只需要存储上三角区的常量一次。可以将下三角矩阵A[1…n][1…n]压缩存储在B[n(n+1)/2+1]中。三角矩阵形式如下图所示。

HePingxxb的博客 2690

Quartus Prime v18.1 standard-QuartusPrimeV18.1标准版安装过程

Quartus Prime v18.1 standard安装破解过程 下载方式1:官网下载: https://fpgasoftware.intel.com/18.1/?edition=standard&platform=windows 下载方式2:可以从我的网盘下载安装包(如果链接未时效的话): 链接:https://pan.baidu.com/s/1bq4_FcNPSflU1zGJv__rvA 提取码:o0in ----------------------------------.

Alonger1988的博客 2万+

广州吉欧电子科技有限公司安卓开发工程师岗位 - 技术核心、职责详解与面试指南

广州吉欧电子科技有限公司招聘安卓开发工程师,该岗位可接收优秀应届生。岗位职责包括:1)负责安卓应用架构设计与开发,确保稳定性和可扩展性;2)功能模块编码实现与测试;3)性能优化与用户体验提升;4)后端接口对接;5)系统版本适配;6)用户反馈处理迭代;7)特殊要求熟悉RTK高精度定位技术原理及使用。该岗位要求扎实的安卓开发技术、良好的架构设计能力、性能优化经验,以及特定领域的RTK专业知识,是一个技术全面且具有专业特色的开发岗位。

郑伟强dev的专栏 154

2.10 BT70 71 72 73+U2 P7-12+单词100

记住思路,要知道上半三角,下半三角,左半三角和右半三角怎么写代码总结发牌逻辑,先按固定顺序生成 52 张牌,再 “起始索引 + 步长 4” 的方式分配给 4 个玩家,保证发牌顺序符合 1→2→3→4 的规则动态规划核心思想:从金字塔的最后一行开始,向上逐层计算每个位置能获得的最大路径和。对于第i行第j列的数字,其最大路径和 = 自身值 + max (正下方位置的最大和,右下方位置的最大和)。最终金字塔顶部(第 0 行第 0 列)的值就是最大路径和。采用双重遍历,来读取矩阵的数据。

weixin_74256798的博客 712

【天气雷达】双偏振产品-差分反射率ZDR详解

双偏振产品-差分反射率ZDR详解。

珞瑜的博客 5412

C++ 特殊矩阵的压缩存储算法

什么是特殊矩阵?C++,一般使用二维数组存储矩阵数据。在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定的规律,称这类型的矩阵为特殊矩阵。为了节省存储空间,可以设计算法,对这类特殊矩阵进行压缩存储,让多个相同的非零数据只分配一个存储空间;对零数据不分配空间。本文将讲解如何压缩这类特殊矩阵,以及压缩后如何保证矩阵的常规操作不受影响。使用二维数组存储矩阵中数据时,如果矩阵中的有效数据较小时,可以采用压缩的方式对其进行存储。本文着重讲解如何使用三元组表方式压缩存储稀疏矩阵。...

y6123236的专栏 903

遗传算法(Genetic Algorithm)详解与实现

遗传算法(Genetic Algorithm, GA)是受自然进化原理启发的一系列搜索算法。通过模仿自然选择和繁殖的过程,遗传算法可以为涉及搜索、优化和学习的各种问题提供高质量的解决方案。同时,它们类似于自然进化,因此遗传算法可以克服传统搜索和优化算法遇到的一些障碍,尤其是对于具有大量参数和复杂数学表示形式的问题。

盼小辉丶的博客 24万+

Python-增加b站视频播放量

如果条件允许的情况下,有代理API更好,每次请求url调用API也更方便。如果没有的话,也不用担心,网上本身也有着很多免费国内代理,不过代理是否可用需要自己花点时间去检测,检测方法笔者这里就不详述了,后面有时间的话会单独针对这一块做详细说明。在开始之前,需准备代理IP。总之,在每次请求url的时候,随机带入某个IP防止被平台检测,便于达到增加播放量预期。大致思路就是针对你的目标代理平台进行IP抓取,并存入到自己本地的IP代理池。本文是该专栏的第1篇,后面会持续更新对应平台干货知识,记得关注。

Python进阶专栏《爬虫实战进阶》,《Pyppeteer从入门到精通》原创作者 5215

特殊矩阵的压缩存储(对称矩阵,三角矩阵,对角矩阵,稀疏矩阵的顺序,链序存储,十字链表的建立)

特殊矩阵的压缩存储,包括对称矩阵,三角矩阵,对角矩阵,稀疏矩阵的顺序,链序存储,十字链表的建立详细代码

qq_61059144的博客 3144

CAPL编程规范与最佳实践

通过本文的学习,读者应该对CAPL编程规范与最佳实践有了初步的了解,并能够编写高质量的CAPL脚本。在实际项目中,CAPL的应用非常广泛,希望读者能够通过不断的学习和实践,掌握更多的CAPL技巧,提高自己的开发能力。

闲人编程的博客 1749

【数据结构】数组和字符串(二):特殊矩阵的压缩存储:对角矩阵——一维数组

本文介绍了对角矩阵的压缩存储,包括初始化、元素设置、元素获取和打印矩阵等。

天地玄黄 魑魅魍魉 风花雪月 商角徵羽 2087

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: 深入解析ATL(第二版ATL8.0)(2.1-2.2节)
下一篇: Anders Hejlsberg谈C#设计过程
mengtech
博客等级 码龄19年 44粉丝 3472原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值