`
txf2004
  • 浏览: 7041993 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

阅读更多
矩阵:
矩阵是数值程序设计中经常用到的数学模型,它是由 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= 01 2 3 4 5 6 7 8 9 10 11 12 1314
(a0前以及a14处放一个0是用来表示在矩阵的左上角及右下角补上的0
稀疏矩阵:
行数m = 6,列数n = 7,非零元素个数t = 6
稀疏矩阵(SparseMatrix)的抽象数据类型
template<classType>
classSparseMatrix...{
intRows,Cols,Terms;//行/列/非零元素数
Trituple<Type>smArray[MaxTerms];
public://三元组表
SparseMatrix(intMaxRow,intMaxcol);
SparseMatrix
<Type>Transpose();//转置
SparseMatrix<Type>//相加
Add(SparseMatrix<Type>b);
SparseMatrix
<Type>//相乘
Multiply(SparseMatrix<Type>b);
}

A的三元组顺序表图示
三元组 (Trituple) 类的定义
template<classType>classSparseMatrix<Type>;
template
<classType>
classTrituple...{
friend
classSparseMatrix<Type>
private:
introw,col;//非零元素所在行号/列号
Typevalue;//非零元素的值
}
稀疏矩阵
转置矩阵
用三元组表表示的稀疏矩阵及其转置:
a.smArrayb.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<classType>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)...{//非零元个数不为零
intCurrentB=0;//转置三元组表存放指针
for(intk=0;k<Cols;k++)//按列号做扫描,做cols次
for(inti=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
}

}

return0;
}

若设稀疏矩阵的行数为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<Cols;i++) rowSize[i]=0;//清零
for(j=0;j<Terms;j++) rowSize[smArray[j].col]++;//统计,注意这里用到的简洁的算法
2.rowstart[]。用它存放事先计算出来的稀疏矩阵各行非零元素在转置矩阵的三元组表中应存放的位置。
rowSize[0]=0;//计算矩阵b第i行非零元素的开始存放位置
for(i=1;i<Cols;i++)rowStart[i]=rowStart[i-1]+rowSize[i-1]
快速转置算法的思想
Ø 建立辅助数组 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<classType>SparseMatrix<Type>
SparseMatrix
<Type>::FastTranspos()...{
//对稀疏矩阵a(*this指示)做快速转置,结果放在b中,时间代价为O(Terms+Columns)。
int*rowSize=newint[Cols];//辅助数组,统计各列非零元素个数
int*rowStart=newint[Cols];//辅助数组,预计转置后各行存放位置
SparseMatrix<Type>b(Cols,Rows);//存放转置结果
b.Rows=Cols;b.Cols=Rows;
b.Terms
=Terms;
if(Terms>0)...{
for(inti=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传送
intj=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;
returnb;
}

在此程序中有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的,如果能够大幅度提高速度,这点空间存储上的开销是值得的。
分享到:
评论

相关推荐

    数组与特殊矩阵基本操作及练习

    在IT领域,数组和特殊矩阵是数据结构中的基础概念...总之,理解数组和特殊矩阵的基本操作及其应用是提升编程技能和解决问题的关键。熟练掌握这些知识点,将有助于你在数据结构和算法的学习以及实际项目开发中游刃有余。

    特殊矩阵存储 数据结构 数组和广义表中内容

    因此,对于稀疏矩阵,我们可以使用三元组(行号,列号,值)或者压缩存储的方式来减少存储需求,例如链表或二维数组。 接下来,广义表是一种更灵活的数据结构,它可以表示包含不同类型和层次的元素。在处理某些复杂...

    矩阵压缩存储与转置(VC6.0++测试通过)

    在计算机科学中,矩阵压缩存储是一种优化数据结构技术,用于减少存储二维数组(如矩阵)所需的内存空间。这种技术尤其适用于稀疏矩阵,即大部分元素为零的矩阵。在本项目"矩阵压缩存储与转置(VC6.0++测试通过)"中...

    C++ 实现稀疏矩阵的压缩存储的实例

    C++ 实现稀疏矩阵的压缩存储的实例 本文主要介绍了C++ 实现稀疏矩阵的压缩存储的实例的相关资料,...本文详细讲解了C++ 实现稀疏矩阵的压缩存储的实例的实现过程,为读者提供了一个实用的稀疏矩阵压缩存储的解决方案。

    C++实现稀疏矩阵的压缩存储实例

    C++实现稀疏矩阵的压缩存储实例 稀疏矩阵是一种特殊的矩阵,在M*N的矩阵中,有效值的个数远小于无效值的个数,并且这些数据的分布没有规律。在压缩存储稀疏矩阵的时候我们只存储极少数的有效数据。稀疏矩阵的压缩...

    稀疏矩阵的转置

    CRS和CCS是两种常用的稀疏矩阵压缩存储方式: - CRS:适合行非零元素较少的情况,存储每个非零元素的列索引和值,以及每行非零元素的结束位置。 - CCS:适合列非零元素较少的情况,存储每个非零元素的行索引和值,...

    数据结构——矩阵.docx

    通过这个实验,学生不仅能够理解矩阵的抽象概念,还能深入理解稀疏矩阵压缩存储的实际应用,并锻炼了编程能力,特别是对算法的理解和实现。在实验结果分析和总结中,学生应关注压缩存储的效率,矩阵转置的时间复杂度...

    稀疏矩阵存储和转置及乘法 c++源代码 原创

    常见的稀疏矩阵存储方法有两种:三元组(Triple)存储和压缩存储(CRS:Compressed Row Storage或CCS:Compressed Column Storage)。在这个C++实现中,很可能采用了CRS方法,因为它更适合进行矩阵运算,如转置和乘法。...

    三对角矩阵压缩存储报告.doc

    【三对角矩阵压缩存储】 在计算机科学中,三对角矩阵是一种特殊的矩阵形式,它在数值计算、线性代数、物理建模等领域有着广泛的应用。这种矩阵的特点是其非零元素仅存在于主对角线及其上方和下方对称的两条对角线上...

    稀疏矩阵的压缩存储和转置

    ### 稀疏矩阵的压缩存储与转置 #### 知识点一:稀疏矩阵的概念 - **定义**:稀疏矩阵是指矩阵中的大部分元素为零或接近于零的矩阵。 - **特点**:非零元素相对较少,且分布没有规律。 - **存储问题**:如果直接使用...

    稀疏矩阵 c++ 三元组表

    方阵压缩存储法是另一种常见的稀疏矩阵存储方式,它通常采用两个数组:一个是存储非零元素的值,另一个是存储对应的行索引。为了节省空间,可以按照列序对非零元素进行排序,使得连续的元素在同一列。 三、C++实现...

    求三对角矩阵的转置矩阵

    在实际应用中,由于三对角矩阵的特殊结构,其存储空间可以通过压缩存储技术来减少,从而提高存储效率和计算速度。 #### 三对角矩阵的基本概念 三对角矩阵是指除了主对角线、主对角线之上第一条对角线以及主对角线...

    C++ 数据结构之对称矩阵及稀疏矩阵的压缩存储

    C++ 数据结构之对称矩阵及稀疏矩阵的压缩存储 对称矩阵和稀疏矩阵是数据结构中两个重要的概念,对称矩阵是指矩阵的转置矩阵等于它本身的矩阵,而稀疏矩阵是指矩阵中非零元素的个数远远小于总元素数的矩阵。压缩存储...

    数组和矩阵

    对数组和矩阵的压缩存储的详细教导,很好的学习,下回分解还有没写完

    用C++实现稀疏矩阵

    因此,为了提高效率,我们通常采用稀疏矩阵的存储结构,如三元组(Triplet)、压缩存储(Compressed Row Storage, CRS)或压缩列存储(Compressed Column Storage, CCS)等。 在这个C++项目中,作者尝试实现了稀疏...

    数据结构课程设计 矩阵的应用 c++

    关键词:矩阵应用、矩阵运算、矩阵转置、矩阵压缩 在这个课程设计中,曾冬芹同学可能需要实现这些基本的矩阵操作,并针对稀疏矩阵进行优化,以提高运算效率。王江涛老师作为指导教师,将指导学生如何在C++中实现...

    稀疏矩阵的存储和乘法

    相比之下,压缩存储方式更适用于计算。 压缩行存储(CRS)是稀疏矩阵的一种常见存储形式,它主要由三部分组成:行索引数组、值数组和列指针数组。行索引数组记录了每行第一个非零元素在值数组中的位置,值数组存储...

    稀疏矩阵的C++实现--课程设计

    常见的存储方法有两种:三元组(Triples)和压缩存储(Compressed Sparse Row, CSR或Compressed Sparse Column, CSC)。在C++中,我们通常会选择CSR或CSC,因为它们更利于实现矩阵运算,如加法、乘法等。 首先,...

Global site tag (gtag.js) - Google Analytics