-
稀疏因子 δ:
在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
。
若 tu
和 mu * 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 ) |