5.3.2 稀疏矩阵及其三元组结构

  • 稀疏因子 δ:
    m x n 的矩阵中,有 t 个元素不为0,那么 δ = t / ( m + n )
    通常当δ <= 0.05 时,称该矩阵为稀疏矩阵

  • 稀疏矩阵的压缩存储:
    只存储矩阵的非零元,因此除了存储非零元的值外,还要存储该非零元所在的行数与列数。

  • 稀疏矩阵的三元组存储结构

#define	MAXSIZE   12500  //设置非零元个数最大值为12500

typedef struct
{
	int i, j;        //该非零元的行下标和列下标
	ElemType  e;	//三元组的元素值
}Triple;		//三元组的一个元素

typedef struct
{
	//非零元三元组表,data[0]未用
	Triple  data[MAXSIZE + 1];
	//该稀疏矩阵的行数,列数,非零元个数
	int  mu, nu, tu;
}TSMatrix;
  • 稀疏矩阵的转置:从M到T
Status TransposeMatrix(TSMatrix M, TSMatrix &T){
if(!M.tu)
{
 return OK;
}
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
q= 1;
for(int col=1; col<=M.nu; col++)
{
	for(int cnt=0; cnt<=M.tu; cnt++)
	{
		if(M.data[cnt].j == col)
		{
			T.data[q].i = M.data[cnt].j;
			T.data[q].j = M.data[cnt].i;
			T.data[q].e = M.data[cnt].e;
			q++;
		}
	}
}
return OK;
}

此算法时间复杂度为 nu * tu,而经典转置算法的时间复杂度为 mu * nu
tumu * nu 一个数量级,那么 mu * nu * nu >> mu * nu,虽然节约了空间,但时间复杂度大大增加。
因此该算法只适用于 tu << mu * nu的情况。

  • 对上面的方法进一步改进:快速转置法
    找到 M 的三元数组每一列的首元素在 T 中的位置,遍历 M
Status FastTransposeMatrix(TSMatrix M, TSMatrix &T)
{
	if(!M.tu)
	{
 		return OK;
	}
	T.mu = M.nu;
	T.nu = M.mu;
	T.tu = M.tu;
	//初始化数组
	for(col=1; col<=M.nu; col++)
	{
		num[col] = 0;
	}
	//求出 M矩阵 每一列有多少元素
	for(cnt=1; cnt<=M.tu; cnt++)
	{
		num[M.data[cnt].j]++;
	}
	//求出 M矩阵 每一列的起始位置(0号单元保留)
	loaction[1] = 1;
	for(col=2; col<=M.nu; col++)
	{
		location[col] = location[col-1] + num[col-1];
	}
	//开始转置
	for(cnt=1; cnt<=M.tu; cnt++)
	{
		tmp = M.data[cnt].j;
		T.data[location[tmp]].e = M.data[cnt].e;
		T.data[location[tmp]].j = M.data[cnt].i;
		T.data[location[tmp]].i = tmp;
		location[tmp]++;
	}
	return OK;
}
  • 行链接信息的三元组表
    多了一个数组,存储每行首个非零元素的位置;便于随机存取每一行的非零元。
    否则当需要按行号存取某一行的非零元时,都需要从头开始进行查找。
typedef struct
{
	Triple data[MAXSIZE+1]; //非零元三元组表
	int rpos[MAXRC+1]; //各行第一个非零元的位置表
	int mu, nu, tu;//行数,列数,非零元个数
}RLSMatrix;
  • 求矩阵的积(经典法)Q = M * N,M为 m1 * n1 矩阵,N为 m2 * n2 矩阵,n1 == m2
for(i=1; i<=m1; i++)
{
	for(j=1; j<=n2; j++)
	{
		Q[i][j] = 0;
		for(k=1; k<=n1; k++)
		{
			Q[i][j] = Q[i][k] + Q[k][j];
		}
	}
}
  • 利用带行链接信息的三元组表求稀疏矩阵的积 ( Q = M * N )
    由于乘积结果 Q 也需要以行序来保存,而 Q 的第n行 与 M 的第n行是相对应的,因此依 M 的行序来依次处理即可,得到的结果也能方便地依行序存入一个顺序表。
    M中每一行的每一个非零元,乘以 N中的某一行,再相加,得到 Q中的一行。
    注意,下面的代码段是类C伪码!!!
Status MultMatrix(RLSMatrix M,RLSMatrix N,
		  RLSMatrix &Q)
{
	if(M.nu != N.mu || M.tu * N.tu == 0)
	{
		return ERROR;
	}
	Q.mu = M.mu;
	Q.nu = N.nu;
	Q.tu = 0;
	// 依 M 的行序依次处理
	// 一次得到 Q 的一行值
	for(arrow=1; arrow<=M.mu; arrow++)
	{
		//累加器清0
		ctemp[] = 0;
		// rpos域 也要在这一过程中完成赋值
		Q.rpos[arrow] = Q.tu + 1;
		if(arrow < M.mu)
		{
			tp = M.rpos[arrow+1];
		}
		else
		{
			tp = Q.tu + 1;
		}
		for(p=M.rpos[arrow]; p<tp; p++)
		{
			brow = M.data[p].j;
			if(brow < N.mu)
			{
				t = N.rpos[brow+1];
			}
			else
			{
				t = N.tu + 1;
			}
			for(q=N.rpos[brow]; q<t; q++)
			{
				// 取列号,也是最终累加结果的列号
				ccol = N.data[q].j;
				ctemp[ccol] += M.data[p].e * N.data[q].e;
			}
		}
		for(ccol=1; ccol<=Q.nu; ccol++)
		{
			if(ctemp[ccol])
			{
				//这组值里面的非0项放到三元组里面
				if(++Q.tu > MAXSIZE)
				{
					return ERROR;
				}
				Q.data[Q.tu] = (arrow, ccol, ctemp[ccol]);
			}
		}
	}
	return OK;
}
时间复杂度
累加器 ctemp 初始化O(M.mu * N.mu)
Q所有非零元O(M.tu * N.tu / N.mu)
压缩存储O(M.mu * N.nu)
总的时间复杂度O(M.mu * N.nu + M.tu * N.tu / N.nu )
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值