稀疏矩阵的压缩存储与快速转置

本文介绍稀疏矩阵的定义及为何需要压缩存储,详细解析三元组法实现矩阵压缩,以及压缩后矩阵的快速转置算法,包括两种不同策略的时间与空间复杂度分析。

稀疏矩阵的压缩存储

什么是稀疏矩阵?
在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵。如下图:

为什么要进行压缩存储?
在稀疏矩阵中,0元素仅占位,无实际含义。用二维数组存储,白白浪费了很多存储空间。故,为了节约存储空间,采用压缩存储。

如何压缩存储?
由上述易知,只记录非0元素就可以压缩矩阵。但元素在矩阵中的位置也是不能丢的。为了确保压缩后矩阵与压缩前的等效性,还需要记录非0元素的行列值。故,每一项非0元素需要记录的就是它自身的数值以及它的行列数。另外,原始矩阵总的行列数和非零元的总数k也需要记录下来。
为了实现上述操作,我们用一个k*3的二维数组来存储。如下图所示。第0项纪录三元组总的行列数,以及总的非0元素数量。
压缩后的稀疏矩阵
这样的压缩存储方式,称为:三元组法

代码如下:

void cunchu(int** m, int row, int col)
{
	int s[MAXSIZE][3];
	int v, i, j, number;
	s[0][0] = row;
	s[0][1] = col;
	v=1;
	for(i=0;i<row;i++)
	{
		for(j=0;j<col;j++)
		{
			if(m[i][j]==1)
			{
				s[v][0] = i;
				s[v][1] = j;
				s[v][2] = m[i][j];
				number++;
				v++;
			}
		}
	}
	s[0][2] = number;
}

压缩后稀疏矩阵的快速转置

转置前的三元组是行主序,这里说的转置要求转置后依旧保持行主序。

思路一:
非原地算法。准备另外一个大小相同的三元组s1。遍历三元组s,每次找到列序最小的那个元素,放进s1中。放的时候注意,行列序号彼此交换。一直重复这一操作,直到s中所有元素均已完成转置。时间复杂度:O(n^2),空间复杂度:O(n)。

思路二:
非原地算法。同样,准备另外一个大小相同的三元组s1。先遍历一遍三元组s,找出同在第i列的有多少个元素(i=1,2,3,4…)。这样就把s1分成了若干个组,第i组的存储空间用于存放列号为i元素,依次排开。再次遍历三元组s,找到元素列号对应的那个组别,按次序放进s1里(放的时候交换行列顺序)。如此便实现了在一次遍历中快速转置三元组。时间复杂度:O(2n),空间复杂度:O(2n)。
代码如下:

void zhuanzhi(int** s, int raw, int col)
{
	int sT[MAXSIZE][3];
	int ad[col];
	int firstad[col];
	int k, i;
	sT[0][0] = s[0][1];
	sT[0][1] = s[0][0];
	sT[0][2] = s[0][2];
	for(i=0;i<col;i++)//address数组初始化
	{
		ad[i]=0;
	}
	k=0;
	for(i=1;i<=s[0][2];i++)//记录列编号相同的个数
	{
		ad[s[i][1]]++;
	}
	firstad[0] = 1;
	for(i=1;i<s[0][1];i++)//记录按列序存储的三元组每列的首地址
	{
		firstad[i] = ad[i-1]+firstad[i-1];
	}
	for(i=1;i<=s[0][2];i++)//把原三元组表中列号相同的元素按次序放到sT表中对应的组中
	{
		sT[firstad[s[i][1]]][0] = s[i][1];
		sT[firstad[s[i][1]]][1] = s[i][0];
		sT[firstad[s[i][1]]][2] = s[i][2];
		firstad[s[i][1]]++;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值