个人笔记--稀疏矩阵的压缩存储与两种转置方法

矩阵

在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。

稀疏矩阵

就是在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵,是一种特殊的矩阵。为了节省空间,我们可以对此类矩阵进行压缩存储。所谓压缩存储,是指为每个非零的元分配一个存储空间,对零元不分配空间。

稀疏矩阵的构建

//定义两个结构体
typedef struct
{
	int x,y;//该非零元素的行下标和列下标
	int v;//该非零元素的值
}Triple;

typedef struct
{
	Triple data[maxsize];//非零元三元组表,其中data[0]没有用到。(maxsize==100)
	int mu,nu,tu;//矩阵的行、列、非零元总数
}TSMarix;

注意:检查非零元素个数是否小于等于行数乘列数;
检查是否能拦截元素下标重复输入;
检查是否能控制输入的非零元素的下标是递增的(即按照行序输入,先输入小的行下标,再输入较大的行下标;行序相等时,先输入小的列下标)。

Status CreateSMatrix(TSMarix &M)
{
	cout<<"请输入矩阵行数,列数,非零元素个数"<<endl;
	do//这里用do-while循环非常友好,当正确输入时退出循环,否则就一直循环
	{
		cin>>M.mu>>M.nu>>M.tu;
		if(M.tu<(M.mu*M.nu))
			break;
		cout<<"输入错误,非零元素个数要小于等于行数乘列数,请从新输入。"<<endl;
	}while(true);
	for(int k=1;k<=M.tu;k++)
	{	
		cout<<"请输入第"<<k<<"个三元组"<<endl;
		int flag=0;
		do
		{
			cin>>M.data[k].x>>M.data[k].y>>M.data[k].v;
			if(M.data[k].x>M.mu || M.data[k].x<=0)
			{
				cout<<"输入行数大于设定行数,请重新输入!"<<endl;
				continue;
			}
			if(M.data[k].y>M.nu || M.data[k].y<=0)
			{
				cout<<"输入列数大于设定行数,请重新输入!"<<endl;
				continue;
			}
			for(int i=1;i<k;i++)
			{
				 if(M.data[k].x==M.data[i].x && M.data[k].y==M.data[i].y)
				{
					cout<<"输入的下标重复,请重新输入!"<<endl;
					flag=1;
					break;
				}
			}
			if(!flag && k!=1)
			{
				if(M.data[k].x<M.data[k-1].x)
				{
					cout<<"行下标输入时要递增输入,请重新输入!"<<endl;
					flag=1;
				}
				else if(M.data[k].x==M.data[k-1].x && M.data[k].y<M.data[k-1].y)
				{
					cout<<"行相同时,列下标输入时要递增输入,请重新输入!"<<endl;
					flag=1;
				}
			}
			if(flag)
			{	
				flag=0;
				continue;
			}
			break;
		}while(true);	
	}	
	return OK;
}		
	return OK;
}

稀疏矩阵的销毁

//啊这,就这啊~
Status DestroySMatrix(TSMarix &M)
{
	M.mu=0;
	M.nu=0;	
	M.tu=0;
	return OK;
}
//就这

输出稀疏矩阵

//因为存储时就是行递增存储,行相等时列递增存储,所以输出也是以这种形式输出
void PrintSMatrix(TSMarix M)
{
	int k=1;
	for(int i=1;i<=M.mu;i++)
	{
		for(int j=1;j<=M.nu;j++)
		{
			if(M.data[k].x==i && M.data[k].y==j)//锁定第k个元素的行和列,
			{
				cout<<M.data[k].v<<' ';//精准输出
				k++;//下一个元素
			}
			else
				cout<<"0 ";//其余部分用0来填充
		}
		cout<<endl;
	}
}

一般转置

Status	TransposeSMatrix(TSMarix M,TSMarix &A)
{
	A.mu=M.nu; A.nu=M.mu; A.tu=M.tu;//稀疏矩阵A的行数就是M的列数,列等同,非零元素个数相同
	if(A.tu)//非零元素个数不为0时
	{
		int q=1;//从A的第一个位置开始存
		for(int col=1;col<=M.nu;++col)//依次搜索M中第col列元素
			for(int p=1;p<=M.tu;++p)//依次搜索M中的第p个非零元素
				if(col==M.data[p].y)//合在一起就是查找M的非零元素中在第col列的非零元素
				{
					A.data[q].x=M.data[p].y;//M的列赋值给A的行
					A.data[q].y=M.data[p].x;//M的行赋值给A的列
					A.data[q].v=M.data[p].v;//非零元素的交接~~
					++q;//抬走,下一个
				}
	}
	return OK;
}

两个for循环,emm时间复杂度有点高,试试下面这个

快速转置

首先定义两个数组
num[i]用来存M中第i列中非零元的个数
cpot[i]指示M中第i列的第一个非零元在存储到B里的恰当位置
显然:
copt[1]=1;
copt[i]=cpot[i-1]+num[i-1];实在不理解就自己找几个数试试就理解了


算了,这里还是给大家试试吧
2*2矩阵
1 2
3 0

col(列)12
num[col]21
copt[col]13

即稀疏矩阵M的三元组为

ijv
111
122
213

稀疏矩阵B(即转置后的M)的三元组为

ijv
111
123
212

先找M中第一个非零元(1)的列(1),由cpot得知应插入到B中的第p(1)个位置,然后cpot[1]++,也就是cpot[1]变为2;
接着找M中第二个非零元(2)的列(2),由cpot得知插入到B中第p(3)个位置
,然后cpot[2]++,也就是cpot[2]变为4;
找到M中最后一个非零元(3)的列(1),因为cpot[1]=2了,所以插入到B中的第p(2)个位置,然后cpot[1]++,也就是cpot[1]变为3;
为什么cpot要加1,想必大家都清楚了吧

Status	FastTransposeSMatrix(TSMarix M,TSMarix &B)
{
	B.mu=M.nu; B.nu=M.mu; B.tu=M.tu;
	int *num,*cpot;
	num=(int *)malloc((M.nu+1)*sizeof(int));	
	cpot=(int *)malloc((M.nu+1)*sizeof(int));
	//就是创建两个长度为M.nu数组,
	if(B.tu)
	{
		for(int col=1;col<=M.nu;++col)
			num[col]=0;//初始化num
		for(int t=1;t<=M.tu;++t)
			++num[M.data[t].y];//求M中每一列中非零元个数
		cpot[1]=1;
		for(int col=2;col<=M.nu;++col)
			cpot[col]=cpot[col-1]+num[col-1];//上面已解释
		for(int p=1;p<=M.tu;++p)//依次遍历M中的非零元,注意是依次
		{
			int Ncol=M.data[p].y;//该非零元的对应列
			int q=cpot[Ncol];//即该列的这个非零元应存到B中的q位置
			B.data[q].x=M.data[p].y;
			B.data[q].y=M.data[p].x;
			B.data[q].v=M.data[p].v;//交接完成~~//注意不是从B的第一个位置开始存到,这一点和一般转置不同
			++cpot[Ncol];//该列的上一个非零元已经存储在B中的q位置了,所以该列的下一个非零元应该存在q+1的位置上。也就是下次再访问到该列时,对应的非零元就存在q+1的位置(因为q位置已经被上一个该列的非零元占了),所以cpot[该列]应自加一下。
		}
	}
	return OK;
}

这不就变成都是1个的for循环了,优化了吧

完整代码

#include<bits/stdc++.h>
#define maxsize 100
#define Status int
#define OK 1
#define ERROR 0
using namespace std;
typedef struct
{
	int x,y;
	int v;
}Triple;

typedef struct
{
	Triple data[maxsize];
	int mu,nu,tu;
}TSMarix;

Status CreateSMatrix(TSMarix &M)
{
	cout<<"请输入矩阵行数,列数,非零元素个数"<<endl;
	do//这里用do-while循环非常友好,当正确输入时退出循环,否则就一直循环
	{
		cin>>M.mu>>M.nu>>M.tu;
		if(M.tu<(M.mu*M.nu))
			break;
		cout<<"输入错误,非零元素个数要小于等于行数乘列数,请从新输入。"<<endl;
	}while(true);
	for(int k=1;k<=M.tu;k++)
	{	
		cout<<"请输入第"<<k<<"个三元组"<<endl;
		int flag=0;
		do
		{
			cin>>M.data[k].x>>M.data[k].y>>M.data[k].v;
			if(M.data[k].x>M.mu || M.data[k].x<=0)
			{
				cout<<"输入行数大于设定行数,请重新输入!"<<endl;
				continue;
			}
			if(M.data[k].y>M.nu || M.data[k].y<=0)
			{
				cout<<"输入列数大于设定行数,请重新输入!"<<endl;
				continue;
			}
			for(int i=1;i<k;i++)
			{
				 if(M.data[k].x==M.data[i].x && M.data[k].y==M.data[i].y)
				{
					cout<<"输入的下标重复,请重新输入!"<<endl;
					flag=1;
					break;
				}
			}
			if(!flag && k!=1)
			{
				if(M.data[k].x<M.data[k-1].x)
				{
					cout<<"行下标输入时要递增输入,请重新输入!"<<endl;
					flag=1;
				}
				else if(M.data[k].x==M.data[k-1].x && M.data[k].y<M.data[k-1].y)
				{
					cout<<"行相同时,列下标输入时要递增输入,请重新输入!"<<endl;
					flag=1;
				}
			}
			if(flag)
			{	
				flag=0;
				continue;
			}
			break;
		}while(true);	
	}	
	return OK;
}	
Status DestroySMatrix(TSMarix &M)
{
	M.mu=0;
	M.nu=0;	
	M.tu=0;
	return OK;
}	
void PrintSMatrix(TSMarix M)
{
	int k=1;
	for(int i=1;i<=M.mu;i++)
	{
		for(int j=1;j<=M.nu;j++)
		{
			if(M.data[k].x==i && M.data[k].y==j)
			{
				cout<<M.data[k].v<<' ';
				k++;
			}
			else
				cout<<"0 ";
		}
		cout<<endl;
	}
}

Status	TransposeSMatrix(TSMarix M,TSMarix &A)
{
	A.mu=M.nu; A.nu=M.mu; A.tu=M.tu;
	if(A.tu)
	{
		int q=1;
		for(int col=1;col<=M.nu;++col)
			for(int p=1;p<=M.tu;++p)
				if(M.data[p].y==col)
				{
					A.data[q].x=M.data[p].y;
					A.data[q].y=M.data[p].x;
					A.data[q].v=M.data[p].v;
					++q;
				}
	}
	return OK;
}

Status	FastTransposeSMatrix(TSMarix M,TSMarix &B)
{
	B.mu=M.nu; B.nu=M.mu; B.tu=M.tu;
	int *num,*cpot;
	num=(int *)malloc((M.nu+1)*sizeof(int));	
	cpot=(int *)malloc((M.nu+1)*sizeof(int));
	if(B.tu)
	{
		for(int col=1;col<=M.nu;++col)
			num[col]=0;
		for(int t=1;t<=M.tu;++t)
			++num[M.data[t].y];
		cpot[1]=1;
		for(int col=2;col<=M.nu;++col)
			cpot[col]=cpot[col-1]+num[col-1];
		for(int p=1;p<=M.tu;++p)
		{
			int Ncol=M.data[p].y;
			int q=cpot[Ncol];
			B.data[q].x=M.data[p].y;
			B.data[q].y=M.data[p].x;
			B.data[q].v=M.data[p].v;
			++cpot[Ncol];
		}
	}
	return OK;
}

int main()
{
	int order,init=0;
	TSMarix M,A,B;
	cout<<"*-----------矩阵-------------*"<<endl;
	cout<<"*-------1、创建矩阵----------*"<<endl;
	cout<<"*-------2、销毁矩阵----------*"<<endl;
	cout<<"*-------3、输出矩阵----------*"<<endl;
	cout<<"*-------4、转置矩阵----------*"<<endl;
	cout<<"*-------5、快速转置矩阵------*"<<endl;
	cout<<"*------输入负数退出程序------*"<<endl;
	do
	{
		cout<<"请输入指令"<<endl;
		cin>>order;
		if(order==0 || order>5)
			cout<<"没有该指令"<<endl;
		else if(order>1 && init==0)
			cout<<"请先创建矩阵"<<endl;
		else if(order>1 && init==2)
			cout<<"矩阵已销毁,请先创建矩阵"<<endl;
		else
			switch(order)
			{
				case 1:
					init=1;
					CreateSMatrix(M);
					cout<<"矩阵创建完成"<<endl;
					break;
				case 2:
					init=2;
					DestroySMatrix(M);
					cout<<"矩阵已销毁"<<endl;
					break;
				case 3:
					cout<<"该矩阵为:"<<endl;
					PrintSMatrix(M);
					break;
				case 4:
					TransposeSMatrix(M,A);
					cout<<"矩阵一般转置后为:"<<endl;
					PrintSMatrix(A);
					break;
				case 5:
					FastTransposeSMatrix(M,B);
					cout<<"矩阵快速转置后为:"<<endl;;
					PrintSMatrix(B);
					break;
				default:
					cout<<"程序已退出"<<endl;
					break;
			}
	}while(order>=0);
	return 0;
}

“每一个不曾起舞的日子,都是对生命的辜负”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值