首先先说一些相关定义:(已经有相关定义认识的可以跳过1、2、3点)
1、稀疏矩阵:
定义非零元素的总数比上矩阵所有元素的总数为矩阵的稠密度。矩阵中非零元素的个数远远小于矩阵元素的总数,并且非零元素的分布没有规律,通常认为矩阵中非零元素的总数比上矩阵所有元素总数的值小于等于0.05时,则称该矩阵为稀疏矩阵(sparse matrix),该比值称为这个矩阵的稠密度;与之相区别的是,如果非零元素的分布存在规律(如上三角矩阵、下三角矩阵、对角矩阵),则称该矩阵为特殊矩阵。
2、三元组:
对于在实际问题中出现的大型的稀疏矩阵,若用常规分配方法在计算机中储存,将会产生大量的内存浪费,而且在访问和操作的时候也会造成大量时间上的浪费,为了解决这一问题,从而产生了多种解决方案。
由于其自身的稀疏特性,通过压缩可以大大节省稀疏矩阵的内存代价。具体操作是:将非零元素所在的行、列以及它的值构成一个三元组(i,j,v),然后再按某种规律存储这些三元组,这种方法可以节约存储空间。例如:
3、三元组顺序表:
假设以顺序存储结构来表示三元组表,可得稀疏矩阵的一种压缩存储方式,称之为三元组顺序表。
ok接下来就是C的代码定义
#define MAXSIZE 999 //稀疏矩阵非零元素最大个数
typedef struct
{
int i,j //非零元素的行和列
DataType v; //非零元素的值
}Triple;
typedef struct //三元组顺序存储结构定义
{
int mu,nu,tu; //稀疏矩阵的行数、列数和非零元素个数
Triple data[Maxsize+1]; //三元组表。data[0]不用
}Matrix;
先给个例子:
4、转置运算
首先,简单的方法是先将ma的i、j互换,但是这样的做法的时间复杂度是O(nu*mu),但是快速转置的时间复杂度是O(nu+tu)。(再提醒一下,mu是行数,nu是列数,tu是非零元素个数。)
快速转置:
接下来是思路:先看下面的图直观了解,上面说的简单做法是将两个for循环套在一起就可以直接实现,快速转置不同,它是先用一个for循环确定原矩阵每一列有多少个元素,就如图中右上角的表格里的nun[col]数组来存储。然后就是pol[col]这个数组了,它是用来记录原矩阵每列中第一个有非零元素在num[col]中的位置,这个有什么用呢?以ma三元组顺序表第一行为例吧(记住data[0]不用,图中是列数行数和个数),读取第一行,j为2,对照表格可知pol[2]=3,所以填到mb的第三列,然后pol[2]++,如果第二列还有非零元素就放到下一位。
上代码:
Status FastTrans(Matrix M,Matrix &N) //&引用应该知道是为什么吧,就是改变外部变量
{
N.mu=M.nu; N.nu=M.mu; N.tu=M.tu;
if(N.tu) //不为空才进行转置
{
for(col=1;col<=M.nu;++col) //肯定又忘了是吧,再提醒一下,mu是行数,nu是列数,tu是非零元素个数。
{
num[col]=0; //先把数组置零
}
for(t=1;t<=M.nu;++t)
{
++num[M.data[t].j]; //记录每一列非零元素个数
}
cpot[1]=1; //这里的cpot就是图中的p[]
for(col=2;col<=M.nu;++col)
cpot[col]=cpot[col-1]+num[col-1];//这个自己验算一下就知道了
//最后一步转置开始
for(p=1;p<=M.tu;++P)
{
col=M.data[p].j; //读取原三元组表p行的列
q=cpot[col]; //匹配是在num中的第几,其实就是在转置后的第几行
N.data[q].i=M.data[p].j;
N.data[q].j=M.data[p].i;
N.data[q].v=M.data[p].v;
++cpot[col];
}
return OK;
}
}