稀疏矩阵

什么是稀疏矩阵?

答: 通常认为稀疏因子<=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;
}

/**********************/



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值