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的,如果能够大幅度提高速度,这点空间存储上的开销是值得的。



解密CANoe数据回放:从BLF到ASC的格式转换与优化策略 本文深入解析CANoe数据回放中BLF与ASC格式的转换与优化策略,帮助工程师高效处理汽车电子测试数据。详细介绍了两种格式的特性、转换方法及性能优化技巧,包括CANoe内置功能、命令行自动化和第三方工具应用,提升故障诊断和系统验证效率。 阅读详情

相关推荐

【scratch音乐课】天空之城:音符与节拍、消息与链表

scratch是一个非常小巧的青少年编程工具,自带程序编写语句,积木式语句非常直观、易用,可创作数学、科学、音乐、绘画等方面作品。本文用scratch“演奏”一首大家非常熟悉的《天空之城》,并向大家介绍一些基本乐理知识,以及scratch中消息、链表的使用。

★·°立芯;︶︵︶ 1万+

矩阵操作

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

chpdirector84的专栏 1407

汽车诊断服务(UDS——0x11服务解析)

ECU复位服务(0x11)详解:该服务支持硬件/钥匙开关/软件三种复位类型(0x01-0x03),复位前需发送肯定响应。请求格式为11+子功能,响应含51+子功能。典型应用需配合安全访问流程,测试时需监控CAN总线通信及DTC状态。复位后ECU将返回默认会话,期间不处理任何诊断请求。服务在编程会话且安全解锁后执行,硬复位会初始化存储数据。

从事汽车行业 980

矩阵的压缩存储

若对一个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

LM358实战:手把手教你搭建电流检测电路(附电阻选型计算)

本文详细解析了使用LM358运算放大器搭建电流检测电路的全过程,包括基础原理、采样电阻选型、放大电路设计及PCB布局技巧。通过实战案例和精确计算,帮助工程师快速掌握低成本、高精度的电流检测方案,适用于电源管理、电机控制等多种应用场景。

weixin_30872157的博客 451

VS2022命令行编译C++报错?一招解决‘fatal error C1034: iostream: 不包括路径集‘

本文针对VS2022命令行编译C++时常见的'fatal error C1034: iostream: 不包括路径集'错误,深入剖析了其根源在于环境变量缺失。文章提供了永久配置用户环境变量(PATH、INCLUDE、LIB)的一劳永逸解决方案,确保在任何终端中都能直接使用cl命令进行编译,并给出了进阶配置与常见错误排查指南。

weixin_29011667的博客 305

面试复习——数据结构(六):数组和广义表

数据结构复习(六):数组和广义表

weixin_45770491的博客 1123

具有I2S输出的多模数字麦克风ICS-43434咪头LR引脚接地或电源WS接LRCLK

ICS-43434 是一款数字 IS 输出底部收音孔麦克风。完整的 ICS-43434 解决方案包括 MEMS 传感器、信号调理、模数转换器、抽取和抗混叠滤波器、电源管理以及行业标准的 24 位 12S 接口。12S 接口允许 ICS-43434 直接连接到数字处理器,例如 DSP 和微控制器,而无需系统中的音频编解码器。

易板 5667

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

新手福利!大龙虾OpenClaw可视化管理工具来了!告别命令行,这个可视化工具让OpenClaw管理变得超简单

还在用命令行管理OpenClaw?🚀 这个跨平台可视化工具支持14+AI模型,一键切换,还能对接微信飞书钉钉等8大消息渠道,让AI助手管理变得简单直观 ✅ 暗色主题护眼舒适,Rust后端高性能低占用,新手也能轻松上手 🎯

XiaoqiangClub的博客 762

华为OD机试新系统真题【迷宫相遇】

华为OD机试 新系统真题【迷宫相遇】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【迷宫相遇】多语言题解。

qq_45776114的博客 770

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

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

y6123236的专栏 903

100天精通Python(可视化篇)——第89天:Bokeh库绘图可视化基础入门(参数说明+案例实战)

专栏导读 一、Bokeh是什么? 二、安装与导入 三、Bokeh接口介绍 四、创建图表 五、添加自定义渲染器 切换主题 添加图例 图例位置 图例方向 图例背景和边界 图例文本的外观 行列布局 网格布局

努力让自己发光,对的人才能迎着光而来 1万+

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

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

qq_61059144的博客 3144

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

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

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

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

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

上一篇: 【Scott Meyers】C++5×5断想之三:C++历史上最重要的软件
下一篇: 深入解析ATL(第二版ATL8.0)(2.1-2.2节)
techweb
博客等级 码龄19年 226粉丝 3842原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值