什么是稀疏矩阵?
答: 通常认为稀疏因子<=0.05时称为稀疏矩阵。
为什么要对矩阵压缩存储?
答:因为在矩阵中经常有很多数值相同,或者数值为零元的矩阵,为了节省空间,可以对这类矩阵进行压缩存储。所谓压缩存储是指, 为多个值相同元只分配一个存储空间,对于元素为零元不分配存储空间。
如何进行稀疏矩阵的压缩存储?
答:只存储矩阵中非零元,同时记录非零元的行和列的位置(i,j)。我们用三元组表来表示例如: ((1,1,2),(1,2,5),(3,1,5));
稀疏矩阵的三元组顺序表存储表示如下:
/******** TripleSparseMatrix.h **********/
#ifndef TRIPLESPARSEMATRIX_H
#define TRIPLESPARSEMATRIX_H
#include "../../01/Status.h"
#include <assert.h>
#include <stdio.h>
/* 稀疏矩阵的三元组顺序表存储表示 */
#define MAXSIZE 12500
typedef int ElemType;
typedef struct{
int i,j;//非零元的行下表和列下表
ElemType e;
}Triple;
typedef struct{
Triple data[MAXSIZE+1];//非零元三元组表,data[0]未用
int mu, nu, tu; //矩阵的行数、列数和非零元个数
}TSMatrix;
//带行链接信息的三元组表为行逻辑链接的顺序表
typedef struct{
Triple data[MAXSIZE+1];//非零元三元组表
int pos[MAXSIZE+1];//各行第一个非零元素的位置表,在data中的序号
int mu,nu,tu;//矩阵的行数、列数和非零元个数
}RLSMstrix;
//创建一个mxn的稀疏矩阵
TSMatrix CreateSMatrix_T(ElemType m, ElemType n);
//从二位数组中创建15x15的稀疏矩阵
TSMatrix CreateTMatirxFrom2DArray(void *pArr2D, int sizeM, int sizeN);
//从二位数组中创建15x15的稀疏矩阵
RLSMstrix CreateRLSMstrixFrom2DArray(void *pArr2D, int sizeM, int sizeN);
//打印稀疏矩阵的值
void PrintSMatrix_T(TSMatrix M);
//打印稀疏矩阵的值
void PrintRLSMstrix_T(RLSMstrix M);
//将 pMat复制给M
Status CopySMatrix_T(TSMatrix pMat, TSMatrix *M);
//M+pMat = Q
Status AddSMatri_T(TSMatrix pMat, TSMatrix M, TSMatrix *Q);
//M-pMat = Q
Status SubSMatrix_T(TSMatrix M, TSMatrix pMat, TSMatrix *Q);
//M*pMat = Q
Status MultSMatrix_T(RLSMstrix M, RLSMstrix N, RLSMstrix *Q);
//矩阵转置
Status TransposeRLSMstrix_T(RLSMstrix M, RLSMstrix *Q);
//销毁矩阵
Status DestroySMatrix_T(TSMatrix *M);
#endif
//稀疏矩阵定义
/********************************/
/**** Status.h ****/
//相关状态码和宏函数列表
#ifndef STATUS_H
#define STATUS_H
/* 状态码 */
#define TRUE 1 //真
#define FALSE 0 //假
#define YES 1 //是
#define NO 0 //否
#define OK 1 //通过
#define ERROR 0 //错误
#define SUCCESS 1 //成功
#define UNSUCCESS 0 //失败
#define INFEASIBLE -1 //不可行
#ifndef _MATH_H_ //系统中已有此状态码定义,要避免冲突
#define OVERFLOW -2 //堆栈上溢
#define UNDERFLOW -3 //堆栈下溢
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
/* 状态码识别类型 */
typedef int Status;
/*宏函数*/
//函数暂停一段时间
#define Wait(x)\
{\
double _Loop_Num_;\
for(_Loop_Num_=0.01; _Loop_Num_<=100000.0*x; _Loop_Num_+=0.01)\
;\
}//设立一个空循环
//摁Enter键继续
#define PressEnter\
{\
fflush(stdin);\
printf("Press Enter...");\
getchar();\
fflush(stdin);\
}
#endif
/******************/
/******** TripleSparseMatrix.c *********/
//函数列表
#ifndef TRIPLESPARSEMATRIX_C
#define TRIPLESPARSEMATRIX_C
#include "TripleSparseMatrix.h"
//创建一个mxn的稀疏矩阵
TSMatrix CreateSMatrix_T(ElemType m, ElemType n){
assert(m>0 && n>0);
TSMatrix *M = (TSMatrix *)malloc(sizeof (TSMatrix));
//M->data=[];
M->mu = m;
M->nu = n;
M->tu = 0;
return *M;
}
//从二位数组中创建15x15的稀疏矩阵
TSMatrix CreateTMatirxFrom2DArray(void *pArr2D, int sizeM, int sizeN){
assert( sizeM > 0 && sizeN > 0 );
TSMatrix *M = (TSMatrix *)malloc(sizeof (TSMatrix));
M->mu = sizeM;
M->nu = sizeN;
M->tu=0;
//遍历数组元素,获取非零元素个数
int m = 0, n = 0;
for( m = 0; m < sizeM; ++m )
for( n = 0; n < sizeN; ++n )
if( ((ElemType *)pArr2D)[sizeN * m + n] != 0 ){
++M->tu;
}
///第二趟遍历, 存储二维矩阵中的非零元素
int nPos = 0;
for( m = 0; m < sizeM; ++m )
for( n = 0; n < sizeN; ++n )
if(((ElemType *)pArr2D)[sizeN * m + n] != 0 )
{
//printf("\n元素:%d", ((ElemType *)pArr2D)[sizeN * m + n]);
M->data[nPos].i= m + 1;
M->data[nPos].j= n + 1;
M->data[nPos].e = ((ElemType *)pArr2D)[sizeN * m + n];
++nPos;
}
return *M;
}
RLSMstrix CreateRLSMstrixFrom2DArray(void *pArr2D, int sizeM, int sizeN){
assert( sizeM > 0 && sizeN > 0 );
RLSMstrix *M = (RLSMstrix *)malloc(sizeof (RLSMstrix));
M->mu = sizeM;
M->nu = sizeN;
M->tu=0;
int m = 0, n = 0;
for( m = 0; m < sizeM; ++m )
for( n = 0; n < sizeN; ++n )
if( ((ElemType *)pArr2D)[sizeN * m + n] != 0 ){
++M->tu;
}
///第二趟遍历, 存储二维矩阵中的非零元素
int nPos = 0;
for( m = 0; m < sizeM; ++m )
for( n = 0; n < sizeN; ++n )
if(((ElemType *)pArr2D)[sizeN * m + n] != 0 )
{
//printf("\n元素:%d", ((ElemType *)pArr2D)[sizeN * m + n]);
M->data[nPos].i= m + 1;
M->data[nPos].j= n + 1;
M->data[nPos].e = ((ElemType *)pArr2D)[sizeN * m + n];
++nPos;
}
return *M;
}
//打印稀疏矩阵的值
void PrintSMatrix_T(TSMatrix M){
int i;
printf("%4s%4s%8s\n", "行", "列", "元素值");
for(i=0;i<M.tu;i++) {
printf("%4d%4d%4d\n",M.data[i].i,M.data[i].j,M.data[i].e);
}
}
void PrintRLSMstrix_T(RLSMstrix M){
int i;
printf("%4s%4s%8s\n", "行", "列", "元素值");
for(i=0;i<M.tu;i++) {
printf("%4d%4d%4d\n",M.data[i].i,M.data[i].j,M.data[i].e);
}
}
//将 pMat复制给M
Status CopySMatrix_T(TSMatrix pMat, TSMatrix *M){
(*M) = pMat;
return OK;
}
//M+pMat = Q
/*
** 参数:M, pMat为相加的稀疏矩阵,Q为结果
** 设置变量m为pmat的当前元素索引,n为M的当前元素索引,q为Q的索引
** 当m,n分别小于对应矩阵的非零元素时,比较当前元素的行列值,
** 当pMat.data[m].i>M.data[n].i时Q.data[q]=PMat[m],q++,m++进入下一次循环
** 当pMat.data[m].i<M.data[n].i时Q.data[q]=PMat[n],q++,n++进入下一次循环
** 当pMat.data[m].i=M.data[n].i时,比较当pMat.data[m].j>M.data[n].j,同理如上
** 循环结束后,若m或者n分别小于对应数列的非零元素个数,则Q.data[q++]=pMat.data[m++]// Q.data[q++]=pMat.data[n++]
*/
Status AddSMatri_T(TSMatrix M, TSMatrix pMat, TSMatrix *Q){
access(pMat.mu != M.mu || pMat.nu!= M.nu);
Q->mu= M.mu;
Q->nu = M.nu;
Q->tu= 0;
int m = 0, q=0, n=0;
while(m <pMat.tu && n <M.tu ){
//比较两矩阵当前元素的行值关系
switch(compare(pMat.data[m].i, M.data[n].i)){
case -1:
Q->data[q++]=pMat.data[m++];
break;
case 0:
switch(compare(pMat.data[m].j, M.data[n].j)){
case -1:
Q->data[q++]=pMat.data[m++];
break;
case 0:
if(pMat.data[m].e + M.data[n].e != 0){
Q->data[q]=pMat.data[m];
Q->data[q].e+=M.data[n].e;
q++;
}
m++;
n++;
break;
case 1:
Q->data[q++]=M.data[n++];
break;
default: break;
}
break;
case 1:
Q->data[q++]=M.data[n++];
break;
default: break;
}
}
while(m<pMat.tu)
Q->data[q++]=pMat.data[m++];
while(n<M.tu)
Q->data[q++]=M.data[n++];
if(q>MAXSIZE){
return ERROR;
}else{
Q->tu=q;
return OK;
}
}
//M-pMat = Q
Status SubSMatrix_T(TSMatrix M, TSMatrix pMat, TSMatrix *Q){
access(pMat.mu != M.mu || pMat.nu!= M.nu);
Q->mu= M.mu;
Q->nu = M.nu;
Q->tu= 0;
int m = 0, q=0, n=0;
while(m <pMat.tu && n <M.tu ){
//比较两矩阵当前元素的行值关系
switch(compare(pMat.data[m].i, M.data[n].i)){
case -1://pMat的行数小于M的行数
Q->data[q]= pMat.data[m];
Q->data[q].e= 0 - pMat.data[m].e;
q++; m++;
break;
case 0:
switch(compare(pMat.data[m].j, M.data[n].j)){
case -1://pMat的列数小于M的列数
Q->data[q]= pMat.data[m];
Q->data[q].e= 0 - pMat.data[m].e;
q++; m++;
break;
case 0:
if(M.data[n].e - pMat.data[m].e != 0){
Q->data[q]=M.data[n];
Q->data[q].e-=pMat.data[m].e;
q++;
}
m++;
n++;
break;
case 1://pMat的列数大于M的列数
Q->data[q++]=M.data[n++];
break;
default: break;
}
break;
case 1://pMat的行数大于M的行数
Q->data[q++]=M.data[n++];
break;
default: break;
}
}
while(m<pMat.tu)
Q->data[q].e=-pMat.data[m].e;
Q->data[q++]=pMat.data[m++];
while(n<M.tu)
Q->data[q++]=M.data[n++];
if(q>MAXSIZE){
return ERROR;
}else{
Q->tu=q;
return OK;
}
}
//M*N = Q
/* 求矩阵乘积,采用行逻辑链接存储表示
** M*N需满足,M的列等于N的行时,可相乘;矩阵Q的列为N的行,行数为M的列数
** 只要有一方为0,则乘积为0
**
*/
Status MultSMatrix_T(RLSMstrix M, RLSMstrix N, RLSMstrix *Q){
access(M.nu != N.mu);
Q->mu = N.nu;
Q->nu = N.mu;
Q->tu=0;
int nnum[N.nu], npos[N.nu], ctemp[M.mu];
int ncol, nq, marrow, mq;
if(N.tu*M.tu==0){
return ERROR;
}
//待补充
//......
return OK;
}
//矩阵转置 Q = M(T)
Status TransposeRLSMstrix_T(RLSMstrix M, RLSMstrix *Q){
if(M.tu<0)
return ERROR;
Q->mu=M.nu;
Q->nu=M.mu;
Q->tu=M.tu;
int col, p, q;
int num[M.nu], pos[M.nu];
for(col=1; col<=M.nu; col++){//对每列非零元素个数初始化
num[col]=0;
}
for(p=0; p<M.tu; p++){//求M中每列所含非零元素个数
printf("%d", M.data[p].j);
++num[M.data[p].j];
}
pos[1]=0;
for (col=2; col<=M.nu; col++){
pos[col] = pos[col-1]+num[col-1];//求M中每一列的第一个费零元在Q.data中的序号
}
for(p=0; p<M.tu; p++){
col = M.data[p].j;
q = pos[col];
Q->data[q].i = M.data[p].j;
Q->data[q].j= M.data[p].i;
Q->data[q].e=M.data[p].e;
++pos[col];
}
Q->tu= p;
return OK;
}
//销毁矩阵
Status DestroySMatrix_T(TSMatrix *M){
M->mu=0;
M->nu=0;
M->tu=0;
return OK;
}
int compare(int a,int b){
if(a==b){
return 0;
}else if (a>b){
return 1;
}else{
return -1;
}
}
#endif
/********************/
/*********** TripleSparseMatrix-main.c ***********/
//主函数
#include <stdio.h>
#include "TripleSparseMatrix.c" //**▲05 数组和广义表**//
int main(int argc, char **argv)
{
TSMatrix M, N, pMat, T;
RLSMstrix M1, N1, T1;
///稀疏因子为 0.098 的二维数组
ElemType arrMat[3][4] = {
{3, 9, 0, 5},
{0, -1, 0, 0},
{2, 0, 0, 8}
};
ElemType arrMat2[3][4] = {
{0, 1, 2, 0},
{6, 1, 0, 8},
{1, 7, 9, 0}
};
ElemType arrMat3[4][3] = {
{1, 5, 9},
{2, 6, 19},
{3, 7, 11},
{4, 8, 12}
};
printf("▼1\n▲函数 CreateSMatrix_T 测试...\n"); //1.函数CreateSMatrix_T测试
{
FILE *fp; //作为输入源
printf("创建两个稀疏矩阵 M、N ...\n");
fp = fopen("TestData_TSMatrix.txt", "r");
CreateSMatrix_T(fp, 2, &M, &N);
fclose(fp);
printf("\n");
}
PressEnter;
printf("▼1\n▲函数 CreateSMatrix_T 测试...\n"); //1.函数CreateSMatrix_T测试
{
printf("创建5x5的稀疏矩阵M\n\n");
N = CreateTMatirxFrom2DArray( arrMat2, 3, 4 );
printf("\n");
}
PressEnter;
printf("▼1\n▲函数 CreateTMatirxFrom2DArray 测试...\n"); //2.函数CreateSMatrix_T测试
{
printf("从二位数组中创建15x15的稀疏矩阵");
pMat = CreateTMatirxFrom2DArray( arrMat, 3, 4 );
}
PressEnter;
printf("▼3\n▲函数 PrintSMatrix_T 测试...\n"); //3.函数PrintSMatrix_T测试
{
printf(" pMat = \n");
PrintSMatrix_T(pMat);
PrintSMatrix_T(N);
printf("\n");
}
PressEnter;
//将 pMat复制给M
printf("▼4\n▲函数 CopySMatrix_T 测试...\n"); //4.函数CopySMatrix_T测试
{
printf("复制 pMat 到 M...\n");
CopySMatrix_T(pMat, &M);
printf(" M = \n");
PrintSMatrix_T(M);
printf("\n");
}
PressEnter;
printf("▼5\n▲函数 AddSMatri_T 测试...\n"); //5.函数AddSMatri_T测试
{
TSMatrix Q1;
AddSMatri_T(N, pMat, &Q1);
printf(" Q1 = N + pMat = \n");
PrintSMatrix_T(Q1);
printf("\n");
}
PressEnter;
printf("▼6\n▲函数 SubSMatrix_T 测试...\n"); //6.函数SubSMatrix_T测试
{
TSMatrix Q2;
SubSMatrix_T(N, pMat, &Q2);
printf(" Q2 = N - pMat = \n");
PrintSMatrix_T(Q2);
printf("\n");
}
PressEnter;
printf("▼1\n▲函数 CreateSMatrix_T 测试...\n"); //1.函数CreateSMatrix_T测试
{
printf("创建5x5的稀疏矩阵T\n\n");
T = CreateTMatirxFrom2DArray( arrMat3, 4, 3 );
printf("\n");
}
PressEnter;*/
printf("▼7\n▲函数稀疏矩阵的乘积 MultSMatrix_T 测试...\n"); //7.函数MultSMatrix_T测试
{
RLSMstrix Q3, M6, N6;
int i;
ElemType arr={
{0, 1, 0},
{1, 0, 1},
{0, 1, 1}
}
ElemType arr2={
{0, 1, 1},
{1, 0, 1},
{1, 1, 1}
}
M6 = CreateRLSMstrixFrom2DArray( arr, 3, 3 ); //创建行逻辑链表
N6 = CreateRLSMstrixFrom2DArray( arr2, 3, 3 ); //创建行逻辑链表
MultSMatrix_T(M6, N6, &Q3);
printf(" Q3 = M6 * T6 = \n");
PrintSMatrix_T(Q3);
printf("\n");
}
PressEnter;
printf("▼8\n▲矩阵快速转置函数 TransposeSMatrix_T 测试...\n"); //8.函数TransposeSMatrix_T测试
{
RLSMstrix Q5, M5;
M5 = CreateRLSMstrixFrom2DArray( arrMat, 3, 4 ); //创建行逻辑链表
PrintRLSMstrix_T(M5);
TransposeRLSMstrix_T(M5, &Q5);
printf(" Q5 = M5(T) = \n");
PrintRLSMstrix_T(Q5);
printf("\n");
}
PressEnter;
printf("▼2\n▲函数 DestroySMatrix_T 测试...\n"); //2.函数DestroySMatrix_T测试
{
printf("销毁 M 前:");
!M.mu && !M.nu && !M.tu ? printf(" M 不存在!!\n") : printf(" M 存在!\n");
DestroySMatrix_T(&M);
printf("销毁 M 后:");
!M.mu && !M.nu && !M.tu ? printf(" M 不存在!!\n") : printf(" M 存在!\n");
printf("\n");
}
PressEnter;
return 0;
}
/**********************/