完整代码请参考GitHub:https://github.com/jie12366/spmatrix.git
由于稀硫矩阵中的零元素个数很多,按一般的矩阵存储方法必然会很浪费空间,为了节省空间,通常用压缩储存的方法来只存储稀硫矩阵的非零元素。这里介绍最常用的三元组表示法。
三元组表示的形式如下:(其中i表示非零元素所在的行,j表示非零元素所在的列,value表示非零元素的值)
(i,j,valueL)
例如这里有个A7*6的稀硫矩阵:
|0 0 -5 0 1 0|
|0 0 0 2 0 0|
|3 0 0 0 0 0|
A |0 0 0 0 0 0|
|12 0 0 0 0 0|
|0 0 0 0 0 4|
|0 0 21 0 0 0|
其对应的三元组表示如下:
B | 0 1 2
——————————————————————————————————
0 | 7 6 7
1 | 0 2 -5
2 | 0 4 1
3 | 1 3 2
4 | 2 0 3
5 | 4 0 12
6 | 5 5 4
7 | 6 2 21
矩阵B的第一行分别是稀硫矩阵A的行数,列数和非零元素的个数,并且三元组是按行号递增排序的,行号相同的按列号递增排序。
稀硫矩阵A及其对应的三元组表示矩阵B的数据类型如下:
/*稀硫矩阵的头文件*/
typedef struct {
int data[100][100]; //存放稀硫矩阵的二维数组
int m,n; //分别存放稀硫矩阵的行数和列数
}matrix;
typedef int spmatrix[100][3]; //稀硫矩阵对应的三元组
那么下面我们来实现如何将一个稀硫矩阵转换为对应的三元组表示。因为稀硫矩阵的三元组表示是按照行优先排序的,故我们必须按顺序逐行扫描,并把非零元素写入三元组表示的数组中。具体实现过程如下:
/*将稀硫矩阵转换为三元组表示 */
void compressMatrix(matrix A,spmatrix B){
int i,j;
int x = 1;
/*按行优先扫描整个稀硫矩阵*/
for(i = 0;i<A.m;i++){
for(j= 0;j<A.n;j++){
/*如果元素非零,则写入三元组表示的数组中*/
if(text[i][j] != 0){
B[x][0] = i; //对应的行号
B[x][1] = j; //对应的列号
B[x][2] = A.data[i][j];//非零元素的值
x++;
}
}
}
/*三元组的第一行分别是稀硫矩阵的行数,列数,非零元素个数*/
B[0][0] = A.m; //行数
B[0][1] = A.n; //列数
B[0][2] = x-1; //非零元素的个数
}
求稀硫矩阵的转置是最常用的算法之一,下面我们来看看在三元组表示下如何实现稀硫矩阵的转置。
这里有个问题:我们要做到转置后非零元素的排列仍然按照行优先的顺序,必须保证每个非零元素在交换行号和列号后能立即确定其在转置矩阵C中的最终位置。
解决方法:首先确定B中的每一列的非零元素的个数,也就是转置后C中每一行非零元素的个数,从而可以计算出C中每一行的非零元素的起始位置。
C中每一行非零元素的起始位置=上一行非零元素的起始位置+上一行非零元素的个数。
具体实现算法及代码解析如下:
/*在三元组表示下实现稀硫矩阵的转置 */
void tranSpmatrix(spmatrix b,spmatrix c){
int i,j,t,m,n;
int x[100]; //该数组用来存放b中每一列非零元素的个数
int y[100]; //该数组用来存放c中每一行非零元素的个数
m = b[0][0]; n = b[0][1]; t =b[0][2];
/*获取稀硫矩阵的行数,列数及非零元素的个数*/
c[0][0] = m; c[0][1] = n; c[0][2] = t;
/*如果非零元素个数大于0*/
if(t>0){
for(i=0;i<n;i++) x[i] = 0; //初始化数组元素为0
/*统计b中每一列非零元素的个数 */
for(i=1;i<=t;i++){
x[b[i][1]] = x[b[i][1]] + 1;
}
/*求矩阵c中每一行非零元素三元组的起始位置 */
y[0] = 1; //初始化为1,实际从第二行开始放非零元素
for(i=1;i<n;i++){
/*该行位置=上一行位置+上一行非零元素个数*/
y[i] = y[i-1] + x[i-1];
}
for(i=1;i<=t;i++){
j = y[b[i][1]]; //令数组下标等于该行的起始位置,b[i][1]是在稀硫矩阵中的实际列号,也就是转置后的行号
/*交换行列写入最终位置*/
c[j][0] = b[i][1];
c[j][1] = b[i][0];
c[j][2] = b[i][2];
y[b[i][1]] = j+1; //如果该行非零元素不止一个,那么该行位置+1,用于把该行元素存在三元组的下一行。
}
}
}
测试运行结果如下: