矩阵的压缩存储
1.特殊矩阵(上三角,下三角化为一维数组存储)
2.稀疏矩阵
(1)三元组表
struct tuple3p
{
int i,j;
elementype val;
}
struct sparmattp
{
int mu,tu,tu;//分别代表稀疏矩阵的行值,列值,非零元个数
tuple3p data[100001];
}a,b;
在这种条件下实现转制和相乘
- 转置(转置前矩阵为M(mn),用sparmattp型的a来描述,转置后矩阵为N(nm),用sparmattp型的b来描述)
方法一:一般转置方法
for (int i=1;i<=m;i++)
for(int j=1;i<=n;j++)
{
N[col][row]=M[row][col];
}
时间复杂度O(m*n)
方法二:按照b.data中三元组的次序依次在a.data中找到相应的三元组进行转置(按照矩阵M的列序进行转置)
void trans_sparmat(sparmattp a,sparmattp b)
{
b.mu=a.nu;b.nu=a.mu;b.tu=a.tu;
if (b.tu!=0)
{
q=1;//q☞b.data中三元组的序号
for(int col=1;col<=a.nu;col+++)//扫描a.data a.nu遍
//(按照a中的列来检索)
for(int p=1;p<=a.tu;p++)//扫描整个a
if (a.data[p].j==col)//符合条件的a元素
{
b.data[q].i=a.data[p].j;
b.data[q].j=a.data[p].i;
b.data[q].val=a.data[p].val;
q++;
}
}
}
复杂度分析:时间复杂度O(mu*tu);
容易看出适用于tu<<mu*nu的情况(元素特别少矩阵特别稀疏),否则复杂度
增加至O(m*n*n);
法三:快速转置
原理:对第一种算法实现优化,预先确定矩阵M中每一列的第一个非零元素在b.data中应有的位置。这样转置时可将a.data中元素快速放到正确位置上去。
新设置两个数组num,cpot
num[col]:矩阵M中第col列中非零元素的个数
cpot[col]:M中第col列的第一个非零元在b.data中的位置
- cpot[1]=1;
- cpot[col]=cpot[col-1]+num[col-1]; col∈[2,a.nu]
void fast_transpos(sparmattp a,sparmattp b)
{
b.mu=a.nu;b.nu=a.mu;b.tu=a.tu;
if (b.tu!=0)
{
q=1;//q☞b.data中三元组的序号
for(int col=1;col<=a.nu;col+++)//扫描a.data a.nu遍
num[col]=0;
for(int t=1;t<=a.tu,t++)
num[a.data[i].j]+=1;
//求M中每一列非零元个数
cpot[1]=1;
for(int col=2;col<=a.nu;col+++)
cpot[col]=cpot[col-1]+num[col-1];
//求第col列中第一个非零元在b.data中的序号
for(int p=1;p<=a.tu;p++)//扫描整个a,转置
{
col=a.data[p].j;//直接知道这个元素是哪一列的
q=cpot[col];
//这一列的元素该在b.data的哪个位置开始存储
b.data[q].i=a.data[p].j;
b.data[q].j=a.data[p].i;
b.data[q].val=a.data[p].val;
cpot[col]+=1;
//下次再遇到这一列的元素就要存储在现在这个位置之后一个位置
}
}
}
复杂度分析:O(mu+tu)
均为单循环,最坏情况(tu=mu*nu)复杂度降为O(m*n),和经典算法复杂度一致
- 相乘
法一:M:m1n1 则N m2n2
当n1=m2时有(最终是一个m1*n2矩阵)
for(int i=1;i<=m1;i++)
for (int j=1;j<=n2;j++)
{
Q[i][j]=0;
for(int k=1;k<=n1;k++)
Q[i][j]+=M[i][k]+N[k][j];
}
时间复杂度O(m1*n1*n2)
很明显这个算法不能用于M,N是稀疏矩阵且用三元组表作存储结构时
优化思路:
(1)0*任何数为0,故稀疏矩阵中只需要a.data中下标为[i][k]和b.data中下标为[k][j]中不为零的元素相乘就可以了
☞为了便于在b.data中寻找矩阵N中第k行的所有非零元,和转置中的思想类似,附设数组rpos[m2+2],num[m2+2]:
- rpos[1]=1;
- rpos[row]=rpow[row-1]+num[row-1]
rpos[row]:N中第row行中第一个非零元在b.data的序号
rpos[row+1]-1:N中第row行中最后一个非零元在b.data中的序号
(为了确定最后一行的最后一个非零元的序号,数组需要开到m2+2,而不是m2+1)