5.3稀疏矩阵压缩存储上

5.3稀疏矩阵压缩存储上

稀疏矩阵是指矩阵中大多数元素为零的矩阵。
从直观上讲,当非零元素个数低于总元素的 30 %时,这样的矩阵为稀疏矩阵。如下图所示的矩阵 M、 N 中,非零元素个数均为 8 个, 矩阵元素总数均为 6 ×7 =42 ,显然 8 /42 <30 %,所以 M、 N 都是稀疏矩阵。
在这里插入图片描述

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

( 1 ) 稀疏矩阵的三元组存储表示

对于稀疏矩阵的压缩存储,采取只存储非零元素的方法。由于稀疏矩阵中非零元素 aij 的分布没有规律,因此,要求在存储非零元素值的同时还必须存储该非零元素在矩阵中所处的 行号和列号的位置信息,这就是稀疏矩阵的三元组表表示法。
在这里插入图片描述

说明:为处理方便,将稀疏矩阵中非零元素对应的三元组按“行序为主序”用一维结构体数组进行存放,将矩阵的每一行(行由小到大)的全部非零元素的三元组按列号递增存放。

由此得到矩阵 M、 N 的三元组表 A 和B。如下图所示。
在这里插入图片描述

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

稀疏矩阵三元组表类型定义如下:

#define MAXSIZE 1000  /*设非零元素的个数最多为 1000*/   
typedef struct   
{   
	int  row,  col;  /*该非零元素的行下标和列下标*/          
	ElementType  e; /*该非零元素的值*/   
}Triple;   
typedef struct 
{  
	Triple   data[MAXSIZE+1];   /* 非零元素的三元组表。data[0]未用*/  
	int   m,  n,  len;          /*矩阵的行数、列数和非零元素的个数*/ 
}TSMatrix; 

在稀疏矩阵情况下,采用三元组表表示法大量节约了存储空间,以图 5.10 中的 M67矩 阵为例,需要 67=42 个存储单元,但 M 采用三元组表 A 存放,共有 8 个非零元素,每个非 零元按占 3 个单元计算,需要 3*8=24 个单元,显然比矩阵常规存储来讲还是大大节省存储。

( 3 )三元组表实现稀疏矩阵的转置运算

需要强调的是,矩阵常规存储是二维的,而三元组存储是一维的,由于矩阵存储结构的变化也带来了运算方法的不同,必需认真分析。下面给出稀疏矩阵的转置运算问题,希望从中体会实现算法的处理思路和改进算法的技术。

矩阵转置指变换元素的位置,把位于( row,col)位置上的元素换到( col,row)位置上,把元素的行列互换。
如图 5 .10 的 6 ×7 矩阵 M,它的转置矩阵就是 7×6 的矩阵 N,并且 N( row,col)= M( col,row),其中,1 ≤ row≤ 7 ,1 ≤ col≤ 6 。

①矩阵转置的经典算法

采用矩阵的正常存储方式(二维数组)实现矩阵转置。

稀疏矩阵转置经典算法

 void TransMatrix(ElementType source[m][n], ElementType dest[n][m]){/*source 和 dest 分别为被转置的矩阵和转置以后的矩阵(用二维数组表示)*/   
	int i, j; 
	for(i=0;i<m;i++) 
		for (j=0;j< n;j++) 
			dest[j][ i]=source[i] [j];   
} 
②三元组表实现稀疏矩阵的转置

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

  • a.矩阵 source 的三元组表 A 的行、列互换就可以得到 B 中的元素,如下图所示。
    在这里插入图片描述
  • b.如 a 操作,转置后矩阵的三元组表 B 中的三元组不是以“行序为主序”进行存放,为保 证转置后的矩阵的三元组表 B 也是以“行序为主序”进行存放,则需要对行、列互换后的三 元组 B 按 B 的行下标(即 A 的列下标)按递增有序进行重新排序,如下图所示。
    在这里插入图片描述
    由此可知,步骤 a 很容易实现,但步骤 b 重新排序势必会大量移动元素,从而影响算法的效率。

为了避免上述简单转置算法中行、列互换后重新排序引起的元素移动,可以采取以下两种处理方法。
方法一:“列序”递增转置法
算法思想
采用按照“被转置矩阵”三元组表 A 的“列序”(即转置后三元组表 B 的 行序)递增的顺序进行转置,并依次送入转置后矩阵的三元组表 B 中,这样一来,转置后矩阵的 三元组表 B 恰好是以“行序为主序”

具体做法
如下图所示,找出第1行全部元素:第一遍从头至尾扫描三元组表A,找出其中所有col =1 的三元组,转置后按顺序送到三元组表 B 中;

在这里插入图片描述
找出第 2 行全部元素:第二遍从头至尾扫描三元组表 A,找出其中所有 col =2 的三元 组,转置后按顺序送到三元组表 B 中;

如此类推…… 找出第k行全部元素:第k遍扫描三元组表A,找出其中所有col =k的三元组,转置后按顺序送到三元组表 B 中。

  • k 的含义:每次扫描三元组表时,寻找的三元组的列值 col=k 的三元组;
  • k 的取值: 1 ≤ k≤ A.n。

为实现处理附设一个当前存放位置计数器j,用于指向当前转置后元素应放入三元组表B 中的位置下标。 j 初值为 1 ,当处理完一个元素后,j 加 1 。

算法描述

void TransposeTSMatrix(TSMatrix  A,  TSMatrix  * B) 
{ /*把矩阵 A 转置到 B 所指向的矩阵中去。矩阵用三元组表表示*/   
	int  i , j, k ;   
	B->m= A.n ; 
	B->n= A.m ; 
	B->len= A.len ;   
	if(B->len>0) 
	{  
		j=1;    /*j 为辅助计数器,记录转置后的三元组在三元组表 B 中的下标值*/ 
		for(k=1; k<=A.n; k++)    /*扫描三元组表 A 共A.n 次,每次寻找列值为 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++;  /*计数器 j 加 1,指向本行下一  个转置后元素的位置下标*/      
				}/*内循环中 if 的结束*/ 
	}/* if(B->len>0)的结束*/ 
}/* end of TransposeTSMatrix */ 

算法分析
算法的时间耗费主要是在双重循环中,其时间复杂度为 O( A.n× A.len)。 最坏情况为:当 A.len=A.m×A.n 时(即矩阵中全部是非零元素),时间复杂度为 O( A.m×A.n2 ), 若采用正常方式经典算法实现矩阵转置的算法时间复杂度为 O( A.m× A.n)。因此,三元组表示法仅适用于存储表示稀疏矩阵。

例5-2 已知A矩阵A.m=100 ,A.n=500 ,A.len=100 ,计算其采用三元组表存储空间和其上 的“列序递增转置法”占用时间情况,并给出对比改进的思路分析。

此矩阵常规存储空间耗费为 A.m×A. n=50000,三元组表存储耗费为A.len×3=300,节省存储。
采用矩阵转置的经典算法时间耗费为 A.m×A. n=50000 次;采用稀疏矩阵的“列序”递增转置算法,时间耗费为 A.n× A.len=50000 次,虽然存储空间减少,但时间复杂度并未降低,原因是要多次(如 A.n=500 次)扫描稀疏矩阵三元组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值