(1)设m*n 矩阵中有t 个非零元素且t远小于m*n,这样的矩阵称为稀疏矩阵。很多科学管理及工程计算中,常会遇到阶数很高的大型稀疏矩阵。如果按常规分配方法,顺序分配在计算机内,那将是相当浪费内存的。为此提出另外一种存储方法,仅仅存放非零元素。但对于这类矩阵,通常零元素分布没有规律,为了能找到相应的元素,所以仅存储非零元素的值是不够的,还要记下它所在的行和列。于是采取如下方法:将非零元素所在的行、列以及它的值构成一个三元组(i,j,v),然后再按某种规律存储这些三元组,这种方法可以节约存储空间。
将三元组按行优先的顺序,同一行中列号从小到大的规律排列成一个线性表,称为三元组表,采用顺序存储方法存储该表。如下图:
可以将其改写成如下的三元组的形式,同时存储器行、列和值,如下:
i | j | v |
1 | 2 | 12 |
1 | 3 | 9 |
3 | 1 | -3 |
3 | 6 | 14 |
4 | 3 | 24 |
5 | 2 | 18 |
6 | 1 | 15 |
6 | 4 | -7 |
对应的三元组的数据结构可以写成如下形式的数据结构:
//定义三元组的数据结构类型
typedef struct{
int i,j; //非零元素的行和列
ElemType e; //非零元素的值
}Triple;
//三元组表的存储类型
typedef struct{
int mu,nu,tu; //矩阵的行、列以及非零元的个数
Triple data[MAXSIZE+1]; //三元组表
}Matrix;
(2)、矩阵的转置
要做到转置要做到三点
①、将矩阵的行列值互换
②、将每个三元组的i、j互换
③、重新排列三元组
如下图:
方法一:
①、将矩阵A的行列转化为矩阵B的列和行
②、以B的行(col)为标准依次遍历三元组的列值(j)的值,即矩阵A的第一列的元素必在B的第一行中,依次赋值。
程序如下:
int TransposeSMatrix(Matrix M,Matrix *X)
{
int col,p,q;
//设置转置矩阵的结构
X->mu=M.nu;
X->nu=M.mu;
X->tu=M.tu;
//矩阵中有非零元素才开始去完成转置工作,否则没有意义
if(X->tu)
{
q=1;
//遍历每一列的非零元素
for(col=1;col<=M.nu;col++)
//扫描三元组中非零元素的个数
for(p=1;p<=M.tu;p++)
if(M.data[p].j==col) //若找到该列的非零元素,开始对该元素的行列转换
{
X->data[q].i=M.data[p].j;
X->data[q].j=M.data[p].i;
X->data[q].e=M.data[p].e;
//继续去对第二个元素进行变化、
q++;
}
}
return OK;
}
方法二:
易看出方法一的时间复杂度主要体现在两次循环上( O(nu*tu) ),当非零元的个数过多的时候(即与mu*nu是同一个数量级的时候),算法的复杂度变为了(o(mu*nu2),虽然此方法在空间上节省了存储空间,但在时间上花费了太大的比重。方法二设置了两个数组num和cpot,num[col]代表矩阵A的每一列的非零元素的个数,cpot[col]表示矩阵A中第col列第一个非零元素的在B对应的三元组的位置,即
cpot[1]=1
cpot[col]=cpot[col-1]+num[col-1] (2<=col<=A.nu)
对应的矩阵A的num和cpot值如下
对应的程序如下所示:
int FastTransposeSMatrix(Matrix M,Matrix *X)
{
int col,k,p,q;
int cpot[10],num[10];
X->mu=M.nu;
X->nu=M.mu;
X->tu=M.tu;
//矩阵中有非零元素才开始去完成转置工作,否则没有意义
if(X->tu)
{
//num代表每一行非零元的个数,初始化为0
for(col=1;col<=M.tu;col++)
num[col]=0;
//计算每一列中非零元的个数
for(k=1;k<=M.tu;k++)
num[M.data[k].j]++;
//初始化cpot为1 cpot代表矩阵M中第col列的第一个非零元素的转置后矩阵X.data的位置
cpot[1]=1;
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];
X->data[q].i=M.data[p].j;
X->data[q].j=M.data[p].i;
X->data[q].e=M.data[p].e;
cpot[col]++;
}
}
return OK;
}
完整程序如下:
#include<stdio.h>
#define OK 1
#define MAXSIZE 100
typedef int ElemType;
//定义三元组的数据结构类型
typedef struct{
int i,j; //非零元素的行和列
ElemType e; //非零元素的值
}Triple;
//三元组表的存储类型
typedef struct{
int mu,nu,tu; //矩阵的行、列以及非零元的个数
Triple data[MAXSIZE+1]; //三元组表
}Matrix;
int TransposeSMatrix(Matrix M,Matrix *X)
{
int col,p,q;
//设置转置矩阵的结构
X->mu=M.nu;
X->nu=M.mu;
X->tu=M.tu;
//矩阵中有非零元素才开始去完成转置工作,否则没有意义
if(X->tu)
{
q=1;
//遍历每一列的非零元素
for(col=1;col<=M.nu;col++)
//扫描三元组中非零元素的个数
for(p=1;p<=M.tu;p++)
if(M.data[p].j==col) //若找到该列的非零元素,开始对该元素的行列转换
{
X->data[q].i=M.data[p].j;
X->data[q].j=M.data[p].i;
X->data[q].e=M.data[p].e;
//继续去对第二个元素进行变化、
q++;
}
}
return OK;
}
int FastTransposeSMatrix(Matrix M,Matrix *X)
{
int col,k,p,q;
int cpot[10],num[10];
X->mu=M.nu;
X->nu=M.mu;
X->tu=M.tu;
//矩阵中有非零元素才开始去完成转置工作,否则没有意义
if(X->tu)
{
//num代表每一行非零元的个数,初始化为0
for(col=1;col<=M.tu;col++)
num[col]=0;
//计算每一列中非零元的个数
for(k=1;k<=M.tu;k++)
num[M.data[k].j]++;
//初始化cpot为1 cpot代表矩阵M中第col列的第一个非零元素的转置后矩阵X.data的位置
cpot[1]=1;
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];
X->data[q].i=M.data[p].j;
X->data[q].j=M.data[p].i;
X->data[q].e=M.data[p].e;
cpot[col]++;
}
}
return OK;
}
//创建系数矩阵,用三元组法表示
void Create(Matrix *M)
{
int i;
printf("请分别输入非零元素的行(mu)、列(nu)以及非零元素的个数(ti):");
scanf("%d %d %d",&M->mu,&M->nu,&M->tu);
printf("请按以下格式输入非零元素(行 列 元素值):\n");
for(i=1;i<=M->tu;i++)
scanf("%d %d %d",&M->data[i].i,&M->data[i].j,&M->data[i].e);
}
//以矩阵的形式输出三元组表示存储的稀疏矩阵
void print(Matrix M)
{
int i,j,k;
//二维数组初始化
int a[10][10]={0};
for(k=1;k<=M.tu;k++)
{
i=M.data[k].i;
j=M.data[k].j;
a[i][j]=M.data[k].e;
}
printf("Matrix is : \n");
for(i=1;i<=M.mu;i++)
{
for(j=1;j<=M.nu;j++)
printf("%4d",a[i][j]);
printf("\n");
}
}
void main()
{
Matrix M,X;
Create(&M);
print(M);
FastTransposeSMatrix(M,&X);
print(X);
}
运行结构如下: