首先我们需要了解什么是稀疏矩阵?
矩阵中非零元素的个数远远小于矩阵元素的总数,并且非零元素的分布没有规律,通常认为矩阵中非零元素的总数比上矩阵所有元素总数的值小于等于0.05时,则称该矩阵为稀疏矩阵(sparse matrix),该比值称为这个矩阵的稠密度。
正因为这样,我们对稀疏矩阵进行存储选择的方法不是平常的直接存储,因为要存储好多非零元素,太浪费空间,所以我们选择采用三元组进行存储。对于一个用二维数组存储的稀疏矩阵 A[m][n],如果假设存储每个数组元素需要 L 个字节,那么存储整个矩阵需要 m*n*L 个字节。但是,这些存储空间的大部分存放的是 0 元素,从而造成大量的空间浪费。为了节省存储空间,可以只存储其中的非 0 元素。
对于矩阵 A[m][n] 的每个元素 a[i][j] ,知道其行号 i 和列号 j 就可以确定其位置。因此对于稀疏矩阵可以用一个结点来存储一个非 0 元素。该结点可以定义:[ i , j , a[i][j] ]。该结点由3个域组成,i:行号,j:列号,a[i][j]:元素值。
这样的结点被称为三元组结点。矩阵的每一个元素都由一个三元组结点 ( i , j ,a[i][j] ) 唯一确定。
首先定义三元组存储的结构体:
typedef struct{
int i,j; //存储每个元素所在的行和列
ElemType e; //存储元素值
}Triple;
typedef struct{
Triple data[MAXSIZE+1];
int mu,nu,tu; //记录矩阵的行数、列数和元素个数
}TSMatrix;
稀疏矩阵的创建:
void CreateMatrix(int m,int n,TSMatrix &M) //创建一个三元组稀疏矩阵
{
int t=1; //矩阵的行列都是从1开始的
M.mu = m;
M.nu = n;
while(scanf("%d",&M.data[t].i) != EOF)
{
cin>>M.data[t].j>>M.data[t].e;
t++;
}
M.tu = t-1;
}
学会了创建稀疏矩阵后,下面我们来想一想怎么得到它的转置矩阵?这时候我们需要考虑了,我们存储稀疏矩阵的时候用的三元组进行存储,目的是节省存储空间。那么我们进行转置的时候也必须要牢记这一点,不能另外开辟多余的空间来进行存储,否则就与我们的初心相违背了。怎么做才能不额外开辟空间或者尽可能使用较少的空间来进行矩阵的转置呢?
下面请看这个算法:
//一个矩阵和它的转置矩阵互为对称矩阵
Status TransposeSMatrix(TSMatrix M,TSMatrix &T)
{
int col,p,q,t;
//一个矩阵和它的转置矩阵的行和列相反
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
if(T.tu)
{
for(col=1;col<=M.nu;++col) //给向量num赋 0
num[col] = 0;
for(t=1;t<=M.tu;++t) //求M中每一列含有的非零元个数
++num[M.data[t].j];
cpot[1] = 1; //给cpot[1]赋初值1
//求第col列中第一个非零元在T.data中的编号
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;
q = cpot[col];
T.data[q].i = M.data[p].j; //交换M和T的行和列
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++cpot[col];
}
}
return OK;
}
稀疏矩阵的转置算法大家慢慢理解,如果大家想通过实验结果来比对该算法,下面我贴出全部代码:
#include<iostream>
#define OK 1
#define ERROR 0
#define Status int
#define ElemType int
#define MAXSIZE 12500
using namespace std;
int num[MAXSIZE];
int cpot[MAXSIZE];
typedef struct{
int i,j;
ElemType e;
}Triple;
typedef struct{
Triple data[MAXSIZE+1];
int mu,nu,tu;
}TSMatrix;
void CreateMatrix(int m,int n,TSMatrix &M) //创建一个三元组稀疏矩阵
{
int t=1; //矩阵的行列都是从1开始的
M.mu = m;
M.nu = n;
while(scanf("%d",&M.data[t].i) != EOF)
{
cin>>M.data[t].j>>M.data[t].e;
t++;
}
M.tu = t-1;
}
Status Print_TSMatrix(TSMatrix G) //打印稀疏矩阵
{
int k=1;
for(int i=1;i<=G.mu;i++)
{
for(int j=1;j<=G.nu;j++)
{
if(G.data[k].i == i && G.data[k].j == j)
{
printf("%4d",G.data[k].e);
k++;
}
else
printf(" 0");
}
cout<<endl;
}
}
//一个矩阵和它的转置矩阵互为对称矩阵
Status TransposeSMatrix(TSMatrix M,TSMatrix &T)
{
int col,p,q,t;
//一个矩阵和它的转置矩阵的行和列相反
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
if(T.tu)
{
for(col=1;col<=M.nu;++col) //给向量num赋 0
num[col] = 0;
for(t=1;t<=M.tu;++t) //求M中每一列含有的非零元个数
++num[M.data[t].j];
cpot[1] = 1; //给cpot[1]赋初值1
//求第col列中第一个非零元在T.data中的编号
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;
q = cpot[col];
T.data[q].i = M.data[p].j; //交换M和T的行和列
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++cpot[col];
}
}
return OK;
}
int main()
{
int m,n;
TSMatrix M,T;
cin>>m>>n;
CreateMatrix(m,n,M);
cout<<endl<<"The matrix M is: "<<endl;
Print_TSMatrix(M);
TransposeSMatrix(M,T);
cout<<"The Transposed matrix is: "<<endl;
Print_TSMatrix(T);
return 0;
}
测试需要的样例:
6 7
1 2 12
1 3 9
3 1 -3
3 6 14
4 3 24
5 2 18
6 1 15
6 4 -7