矩阵
在数学中,矩阵(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(列) | 1 | 2 |
---|---|---|
num[col] | 2 | 1 |
copt[col] | 1 | 3 |
即稀疏矩阵M的三元组为
i | j | v |
---|---|---|
1 | 1 | 1 |
1 | 2 | 2 |
2 | 1 | 3 |
稀疏矩阵B(即转置后的M)的三元组为
i | j | v |
---|---|---|
1 | 1 | 1 |
1 | 2 | 3 |
2 | 1 | 2 |
先找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;
}
“每一个不曾起舞的日子,都是对生命的辜负”