一、矩阵的压缩存储:
在编写程序时往往都是二维数组表示矩阵,然而在数值分析中经常出现一些阶数很高的的矩阵同时在距震中有很多值相同的元素,或者是零元素,为了节省空间,可以对这类矩阵进行压缩存储,所谓的压缩存储就是,多个值相同的元之分配一个存储空间,对零元不分配空间。
二、矩阵分类:
1、假如值相同的元素或者零元素在矩阵中的分配有一定的规律,则我们称此类矩阵为特殊矩阵;反之,称为稀疏矩阵。
2、n阶对称矩阵
满足Aij = Aji 1<=i,j<=n;
3、稀疏矩阵:非零元较零元少,且分布没有规律。
三、稀疏矩阵:
1、假设在mn的矩阵中,有t个元素不为零。
& = t/(mn).
称&为矩阵的稀疏因子。通常认为&<=0.05时称为稀疏矩阵。
四、三元组:
1.存储非零元素
2.同时存储该非零元素所对应的行下标和列下标
3.稀疏矩阵中的每一个非零元素需由一个三元组(i, j, aij)唯一确定,稀疏矩阵中的所有非零元素构成三元组线性表,三元组中的i就是行下标,j是列下标,aij是对应的元素值。
4、结构描述:
struct node
{
int i,j; //定义三元组的行、列号
int v; //三元组的值
};
struct sparmatrix
{
int rows,cols; //稀疏矩阵的行、列数
int terms; //稀疏矩阵的非零元个数
struct node data[maxsize]; //存放稀疏矩阵的三元组表
};
五、代码实现:
1、检测是否为稀疏矩阵:
int examine()
{
int x=0; //赋初值为0
for(x=0;x<=99;x++)
{
stu[x].value=0;
}
float t=0; //非零元素个数
float v; //非零元素占有率
for(int i=0;i<m;i++) //遍历矩阵元素
{
for(int j=0;j<n;j++)
{
if(a[i][j]!=0) //如果该矩阵元素不为零
t++; //非零元素个数加一
}
}
if((v=t/(m*n))<=0.05) //计算矩阵非零元素占有率
{
printf("该矩阵为稀疏矩阵%f\n",v);
return 1;
}
else
{
printf("该矩阵不是稀疏矩阵\n");
return 0;
}
}
2、压缩矩阵:
void compress()
{
int t=0;
for(int r=0;r<m;r++)
{
for(int c=0;c<n;c++)
{
if(a[r][c]!=0) //只存储不为零的元素
{
stu[t].i=r; //行下标
stu[t].j=c; //列下标
stu[t].value=a[r][c];//压缩后矩阵的值用二维数组的下标表示
t++;
}
}
}
}
3、转置矩阵:
void zhuanzhi()
{
int x=0; //赋初值为0
int t=0;
int num[10]={0,0,0,0,0,0,0,0,0,0}; //每一列非0的数目
int j;
for(x=0;x<=99;x++)
{
stu1[x].value=0;
}
for(int j=0;j<n;j++) //遍历矩阵元素
{
for(int i=0;i<m;i++)
{
if(a[i][j]!=0) //非零元素出现
{
num[j]++; //数组num第j个元素变为1
t++; //非零元素数目加一
}
}
}
int cpot[10]={0,0,0,0,0,0,0,0,0,0};
cpot[0]=0;
for(j=1;j<n;j++)
{
cpot[j]=cpot[j-1]+num[j-1];//找到表中j列最小值1所在的三元组
}
int col=0;
int q=0;
for(int k=0;k<t;k++)
{
col=stu[k].j;
q=cpot[col];
stu1[q].i=stu[k].j; //i,j位置互换
stu1[q].j=stu[k].i;
stu1[q].value=stu[k].value;//值互换
++cpot[col];
}
}
4、完整代码如下,读者可自取:
#include<stdio.h>
//判断该矩阵是否为稀疏矩阵
#define m 10
#define n 10
int a[m][n]={
{1,0,0,0,0,0,0,0,0,0}, //自定义数组
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,7,0},
{0,0,0,0,0,0,8,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
};
struct three
{
int i,j; //定义矩阵下标
int value; //下标对应值
};
struct three stu[100];
struct three1
{
int i,j; //定义转置矩阵元素的下标
int value; //转置矩阵下标对应值
};
struct three1 stu1[100];
//检测
int examine()
{
int x=0; //赋初值为0
for(x=0;x<=99;x++)
{
stu[x].value=0;
}
float t=0; //非零元素个数
float v; //非零元素占有率
for(int i=0;i<m;i++) //遍历矩阵元素
{
for(int j=0;j<n;j++)
{
if(a[i][j]!=0) //如果该矩阵元素不为零
t++; //非零元素个数加一
}
}
if((v=t/(m*n))<=0.05) //计算矩阵非零元素占有率
{
printf("该矩阵为稀疏矩阵%f\n",v);
return 1;
}
else
{
printf("该矩阵不是稀疏矩阵\n");
return 0;
}
}
//压缩存储
void compress()
{
int t=0;
for(int r=0;r<m;r++)
{
for(int c=0;c<n;c++)
{
if(a[r][c]!=0) //只存储不为零的元素
{
stu[t].i=r; //行下标
stu[t].j=c; //列下标
stu[t].value=a[r][c];//压缩后矩阵的值用二维数组的下标表示
t++;
}
}
}
}
void display() //打印三元组
{
int x=0;
printf("压缩矩阵的三元组为:\n");
for(x=0;x<=99;x++)
{
if(stu[x].value==0) break;//如果值为0,跳出循环
printf("{%d,%d,%d} ",stu[x].i,stu[x].j,stu[x].value);//如果不为零,输出三元组(横纵坐标,值)
}
printf("\n");
}
//转置矩阵
void zhuanzhi()
{
int x=0; //赋初值为0
int t=0;
int num[10]={0,0,0,0,0,0,0,0,0,0}; //每一列非0的数目
int j;
for(x=0;x<=99;x++)
{
stu1[x].value=0;
}
for(int j=0;j<n;j++) //遍历矩阵元素
{
for(int i=0;i<m;i++)
{
if(a[i][j]!=0) //非零元素出现
{
num[j]++; //数组num第j个元素变为1
t++; //非零元素数目加一
}
}
}
int cpot[10]={0,0,0,0,0,0,0,0,0,0};
cpot[0]=0;
for(j=1;j<n;j++)
{
cpot[j]=cpot[j-1]+num[j-1];//找到表中j列最小值1所在的三元组
}
int col=0;
int q=0;
for(int k=0;k<t;k++)
{
col=stu[k].j;
q=cpot[col];
stu1[q].i=stu[k].j; //i,j位置互换
stu1[q].j=stu[k].i;
stu1[q].value=stu[k].value;//值互换
++cpot[col];
}
}
//输出转置后的三元组
void display1()
{
int x=0;
printf("转置以后的三元组为:\n");
for(x=0;x<=99;x++)
{
if(stu1[x].value==0) break; //矩阵元素值为零,跳出循环
printf("{%d,%d,%d} ",stu1[x].i,stu1[x].j,stu1[x].value);//不为零,输出三元组(坐标+值)
}
printf("\n");
}
//输出矩阵中所有元素的三元组
void display2()
{
int d,b;
for(d=0;d<m;d++)
{
for(b=0;b<m;b++)
{
printf("%d ",a[d][b]);
}
printf("\n");
}
}
int main()
{
display2();
if(examine()==1) //检测通过
{
compress(); //压缩
display(); //列出
zhuanzhi(); //转置
display1();
}
}