我们假设在m*n的矩阵中,有t个元素不为0,令a=t/(m*n),称a为矩阵的稀疏因子,通常认为a<=0.05时称为稀疏矩阵。
为了节省存储空间,我们对稀疏矩阵进行压缩存储——只存储稀疏矩阵的非零元。因此,除了存储非零元的值之外,还必须同时记下它所在行和列的位置,反之,一个三元组(i, j, aij)惟一确定了矩阵A的一个非零元。由此,稀疏矩阵可由表示非零元的三元组及其行列数惟一确定。
例如,下列三元组表
((1,2,12),(1,3,9),(3,1,-3),(3,6,14),(4,3,24),(5,2,18),(6115),(6,4,7))
加上(6,7)这一对行、列值便可作为下图矩阵M的另一种描述。
假设以顺序存储结构来表示三元组表,则可得稀疏矩阵的一种压缩存储方式——我
们称之为三元组顺序表。
在此,data域中表示非零元的三元组是以行序为主序顺序排列的。下面将讨论在这种压缩存储结构下如何实现矩阵的转置运算。
显然,一个稀疏矩阵的转置矩阵仍然是稀疏矩阵。假设a和b是Tsmatrix型的变量,分别表示矩阵M和T。那么,如何由a得到b呢?
从分析a和b之间的差异可见只要做到:(1)将矩阵的行列值相互交换;(2)将每个三
元组中的I和j相互调换;(3)重排三元组之间的次序便可实现矩阵的转置。前二条是容易做到的,关键是如何实现第三条。即如何使b. data中的三元组是以T的行(M的列)为主序依次排列的。
下面我讲一个自认为十分巧妙也是很好理解的一种处理办法:
我们在a中即矩阵M中,以列序为主序对非零元进行顺序排列,很好理解,这就是M进行转置运算后得到的矩阵T中以行序为主序对非零元进行顺序排列相应的序列。即实现了b. data中的三元组是以T的行(M的列)为主序依次排列的。
思路如下:
为了确定a中非零元以列序为主序进行顺序排列的序列,在转置前,应先求得M的每一列中非零元的个数,进而求得每一列的第一个非零元在b. data中应有的位置。
在此,需要附设num和cpot两个向量。num[col]表示矩阵M中第col列中非零元
的个数,cpot[col]指示M中第col列的第一个非零元在b. data中的恰当位置。代码实现如下:
for(col=0;col
for(t=0;t
cpot[0]=0;//第一列的第一个非零元计数为0
for(col=1;col
cpot[col]=cpot[col-1]+num[col-1];//从第二列开始,每一列第一个非零元序列为上一列第一个非零元序列加上是上一列的非零元数
}
for(t=0;t
col=M.data[t].j;
q=cpot[col];
T.data[q].i=M.data[t].i;
T.data[q].j=M.data[t].j;
T.data[q].e=M.data[t].e;
++cpot[col];//这一列下一个非零元序列在是一个基础上加一
}
全部参考代码:
#include
#include
#include
#include
#define ElemType int
#define MAXSIZE 100
typedef struct{
int i,j;
ElemType e;
} Triple;
typedef struct{
Triple data[MAXSIZE];
int mu,ru,tu;//矩阵的行数、列数和非零元个数
}TSMatrix;
int main(){
TSMatrix M,T;
int col,num[100],cpot[100],t,q,i,j,m,n;
int b[7][6];
int a[6][7]={
1,12,9,0,0,0,0,
0, 0,0,0,0,0,9,
-3,0,0,0,0,14,0,
0,0,24,0,0,0,0,
0,18,0,0,0,9,0,
15,0,0,-7,0,0,9
};
M.mu=6;
M.ru=7;
M.tu=0;
for(i=0;i<6;i++){
for(j=0;j<7;j++){
if(a[i][j]!=0){
M.data[M.tu].i=j;
M.data[M.tu].j=i;
M.data[M.tu].e=a[i][j];
M.tu++;
}
}
}
T.ru=M.mu;
T.mu=M.ru;
T.tu=M.tu;
if(T.tu){
for(col=0;col
for(t=0;t
cpot[0]=0;
for(col=1;col
cpot[col]=cpot[col-1]+num[col-1];
}
for(t=0;t
col=M.data[t].j;
q=cpot[col];
T.data[q].i=M.data[t].i;
T.data[q].j=M.data[t].j;
T.data[q].e=M.data[t].e;
++cpot[col];
}
}
memset(b,0,sizeof(int)*7*6);
for(t=0;t
m=T.data[t].i;
n=T.data[t].j;
b[m][n]=T.data[t].e;
printf("%d,%d,%d\n",T.data[t].i,T.data[t].j,T.data[t].e);//输出非零值在原矩阵中的位置及数值
}
for(i=0;i
for(j=0;j
printf("%3d\ ",b[i][j]);
printf("\n");
}
return 0;
}