【定义】
所谓稀疏矩阵,假设在m×n矩阵中,有t个元素不为零,令δ=t/(m×n),δ为矩阵的稀疏因子,如果δ≤0.05,则称矩阵为稀疏矩阵。通俗的来讲,若矩阵中大多数元素的值为零,只有很少的非零元素,这样的矩阵就是稀疏矩阵。
如图就是一个稀疏矩阵
【三元组表示】
为了节省内存单元,需要对稀疏矩阵进行压缩存储。在进行压缩存储的过程中,我们可以只存储稀疏矩阵的非零元素,为了表示非零元素在矩阵中的位置,还需存储非零元素的行号和列号(i,j)。这样通过存储非零元素的行号、列号和元素值即可将稀疏矩阵压缩存储,我们把这种存储方式称为稀疏矩阵的三元组表示。
三元组的结点结构如图所示。
上面的稀疏矩阵用三元组表示如下:
((0,3,5),(1,1,8),(2,2,6),(2,3,3),(2,3,3),(3,0,9),(3,4,5),(4,2,9),(4,3,3),(5,4,1))
若将这些三元组按照行序为主序存放在一维数组中,如图所示,我们将这种采用顺序存储结构的三元组称为三元组顺序表,其中k表示一维数组的下标。
三元组顺序表的类型用C语言描述如下:
#define MAXSIZE 100
typedef struct
{
int i;
int j;
DataType e;
}Triple;
typedef struct
{
Triple data[MAXSIZE];
int m;
int n;
int len;
}TriSeqMatrix;
【稀疏矩阵的转置】
稀疏矩阵(三元组表示)的基本运算包含创建三元素矩阵、三元组的销毁矩阵、三元组的复制、输出等基本运算(TriSeqMatrix.h)。
稀疏矩阵的转置。稀疏矩阵的转置就是要将矩阵中元素由原来的存放位置(i,j)变成(j,i),也就是说将元素的行列互换。例如下图就是一个6×7矩阵经过转置后变为7×6的矩阵,并且矩阵的元素也要以主对角线为基准进行变换。
将稀疏矩阵转置的方法:
将三元组中的元素进行行列互换即可得到转置后的矩阵。(i,j,e)→(j,i,e)
下图展示了一个矩阵进行转置的过程:
行列下标互换后,为了保证转置后的矩阵仍然按照行序优先排列,还需要将行、列下标重新排序。另外,还有一种方法可以减少这种排序,那就是以列优先顺序进行转置,转置后的三元组顺序表刚好是以行序优先存放的。
算法思想:
扫面三元组顺序表M,找到j=0的元素,将行号和列号互换后存入到三元组N中。再第二趟扫面M,找到j=1的元素,将行号和列号互换存入到三元组顺序表N中。依此类推,直到所有元素都存放在N中。
如图所示
稀疏矩阵转置的算法实现如下:
void TransposeMatrix(TriSeqMatrix M,TriSeqMatrix *N)
/*稀疏矩阵的转置*/
{
int i,k,col;
N->m=M.n;
N->n=M.m;
N->len=M.len;
if(N->len)
{
k=0;
for(col=0;col<M.n;col++) /*按照列号扫描三元组顺序表*/
for(i=0;i<M.len;i++)
if(M.data[i].j==col) /*如果元素的列号是当前列,则进行转置*/
{
N->data[k].i=M.data[i].j;
N->data[k].j=M.data[i].i;
N->data[k].e=M.data[i].e;
k++;
}
}
}
通过分析该转置算法,其时间复杂度主要是在for循环语句上,因此算法的时间复杂度为O(n*len)。当非零元素的个数len与m*n同数量级时,算法的时间复杂度就变为O(m*n*n)。如果稀疏矩阵仍然采用二维数组存放,则转置算法为:
for(col=0;col<M.n;++col)
for(row=0;row<M.len;row++)
N[col][row]=M[row][col];
上述算法的时间复杂度为O(n*m升}4、}此可以看出,采用三元组顺序表示虽然节省了存储空问,但时间复杂度却增加了。在算法设计过程中时间复杂度和空间复杂度就是一个此消彼长的过程,降低了时间复杂度,就势必以牺牲空间复杂度为代价,反之亦然,算法设计就是时间复杂度和空间复杂度的一种折中考虑为了降低时间复杂度,可以考虑用稀疏矩阵的快速转置算法。