1. 什么是稀疏矩阵?
假设m行n列的矩阵含t个非零元素,则称
a = t / (m × n) 为稀疏因子
通常认为a≤ 0.25的矩阵为稀疏矩阵。(本人老师PPT上是这样写的)
2 .稀疏矩阵压缩存储的原则?
只存储矩阵的行列维数,以及每个非零元的行列下标及其值。
例如,稀疏矩阵M如下:
3.三元组顺序表
(1)三元组顺序表类型描述
typedef int ElementType;
typedef struct
{
int row,col;/* 所有元的行下标和列下标 */
ElementType e;
}Triple;
typedef struct
{
Triple data[MAXSIZE + 1];/* 三元组表,data[0]未用 */
int rows,cols,nums;/* 矩阵的行数、列数和非零元个数 */
}TSMatrix;
(2)矩阵的转置运算
一般的矩阵转置运算:
for(int i = 0;i < cols;i++)
for(int j = 0;j < rows;j++)
{
dest[j][i] = source[i][j];
}
时间复杂度为T(n) = O(m×n)
那么,如何在压缩存储结构下实现矩阵的转置运算呢?
这里有两种算法。
方法一:简单转置算法
描述:N中的第1个非零元是M中第1列的第1个非零元
N中的第2个非零元是M中第1列的第2个非零元或M中第2列的第1个非零元…
为找到M中每一列所有非零元素,需对其三元组表从第1个开始起扫描一遍。
代码:
void CreateSMatrix(TSMatrix *M)/* 三元组压缩存储结构的矩阵的创建 */
{
int k,p = 1,nums = 0;
printf("请输入行数列数和非零元个数:");
scanf("%d %d %d",&M->rows,&M->cols,&M->nums);
for(int i = 1;i <= M->rows;i++)
for(int j = 1;j <= M->cols;j++)
{
scanf("%d",&k);
if(k != 0)
{
nums++;
M->data[p].row=i;
M->data[p].col=j;
M->data[p++].e=k;
}
}
M->nums=nums;
printf("矩阵创建成功,如下:\n");
}
void PrintSMatrix(TSMatrix *M)/* 打印压缩存储后的M */
{
int zero = 0,p = 1;
for(int i = 1;i <= M->rows;i++)
{
for(int j = 1;j <= M->cols;j++)
{
if((i == M->data[p].row) && (j == M->data[p].col) && (p <= M->rows * M->cols))
{
printf("%-3d",M->data[p++].e);
}
else printf("%-3d",zero);
}
printf("\n");/* 一行一行的输出 */
}
}
void TransposeSMatrix_Simple(TSMatrix *M,TSMatrix *N)/* 简单转置算法 */
{
N->rows = M->cols;
N->cols = M->rows;
N->nums = M->nums;
if(N->nums)
{
int q = 1;
for(int col = 1;col <= M->cols;++col)
{
for(int p = 1;p <= M->nums;++p)
{
if(M->data[p].col == col && M->data[p].e != 0)
{
N->data[q].row = M->data[p].col;
N->data[q].col = M->data[p].row;
N->data[q].e = M->data[p].e;
q++;
}
}
}
}
}
时间复杂度:T(n) = O(M->cols × M->nums)
若nums与M->rows× M->rcols同数量级,
则T(n) = O(M->cols^2 × M->rows)
所以,改算法仅适用于 nums 远小于 M->rows× M->rcols
方法二:快速转置算法
描述:N中的第1个非零元是M中第1列的第1个非零元
N中的第2个非零元是M中第1列的第2个非零元或M中第2列的第1个非零元…
为找到M中每一列所有非零元素,需对其三元组表从第1个开始起扫描一遍。
代码:
void TransposeSMatrix_Fast(TSMatrix *M,TSMatrix *N)/* 快速转置算法 */
{
N->rows = M->cols;
N->cols = M->rows;
N->nums = M->nums;
int num[MAXSIZE],pos[MAXSIZE],q = 1,col;
for(col = 1;col <= M->cols;col++) num[col] = 0;
for(int t = 1;t <= N->nums;t++) ++num[N->data[t].col];/* 求N中每一列所含非零元的个数 */
pos[1] = 1;
for(col = 2;col <= M->cols;col++)
pos[col] = pos[col - 1] + num[col - 1];
for(int p = 1;p <= N->nums;p++)
{
col = M->data[p].col;
q = pos[col];
N->data[q].row = M->data[p].col;
N->data[q].col = M->data[p].row;
N->data[q].e = M->data[p].e;
pos[col]++;
}
}
时间复杂度为:T(n) = O(M->cols + M->nums)
若nums与M->rows× M->rcols同数量级,
则T(n) = O(M->cols × M->rows)
和非压缩矩阵的转置算法的时间复杂度相同
- 要注意,我这里的函数参数用的都是指针类型,便于传参,也可以让M作为形参,N作为实参。
可能表述有误,还望及时指正。这是个人学习的一点总结,辛苦你们看了。