稀疏矩阵是矩阵中一种特别的矩阵,主要特点是:非零元素占矩阵所有元素的比例极少。那么,对于这种矩阵的存储,就存在很多很节省空间的方式,核心要点也就是舍弃那些无用元素即零元素,下面将以两种存储方式进行程序设计的实现:
关于稀疏矩阵的COO存储和CSR存储方式,以及不同存储方式的转置矩阵,使用C语言实现逻辑功能,稀疏矩阵二维阵列及行列长度均保存在input.bat文件中,文件见问末,详细代码如下:
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#define MAXSIZE 100 //最大非零元数
//COO格式
typedef struct Triple { //三元组
int i, j; //行列下标
float e; //非零元元素值
}Triple;
typedef struct TSMatrix { //矩阵
Triple data[MAXSIZE + 1]; //三元组表
int mu, nu, tu; //矩阵的行列数、非零元个数
}TSMatrix;
//CSR格式
typedef struct Tuple { //二元组
int j; //列下标
float e; //非零元元素值
}Tuple;
typedef struct Dista { //第一个非空字符距离
int l; //长度
}Dista;
typedef struct CSRstorage { //矩阵
Tuple data[MAXSIZE + 1]; //二元组表,替代两个有关系的一维表
Dista dist[MAXSIZE + 1]; //距离数组
int mu, nu, tu; //矩阵的行列数、非零元个数
}CSRstorage;
void main()
{
//声明矩阵
TSMatrix M,Tr;//COO
CSRstorage Xs,XsZ;//CSR
int i,j,t;
//打印学生学号和姓名
printf("学号:2019xxx\t姓名:xxx\n");
//***************************************************************************
//读取bat文件内容,并以COO格式存儲
//***************************************************************************
int m,n;//长度和宽度
float sp[15][15]; //自定义二维数组大小
FILE *p1 = fopen("input.bat", "r"); //input.bat文件放在.c文件所在的文件夹中
if (p1==NULL) //检测是否成功打开
{
printf("Open failed\n");
}
//读取数组长度
fscanf(p1,"%d",&m);
fscanf(p1,"%d",&n);
M.mu = m;
M.nu = n;
//二维数读取矩阵值,并以COO格式存储
int temp = 0;
for (i = 0; i<15; i++)
{
for (j = 0; j<15; j++)
{
fscanf(p1, "%f", &sp[i][j]); //读入input.bat数据给数组sp
if(!(sp[i][j]<0.000001&&sp[i][j]>-0.000001))
{
M.data[temp].i = i;
M.data[temp].j = j;
M.data[temp].e = sp[i][j];
temp = temp + 1;
}
}
}
M.tu = temp;
fclose(p1);//释放指针
//***************************************************************************
//打印三个向量,非零
//***************************************************************************
printf("COO,打印三个向量如下:\n");
printf("(%d,%d,%g)\t",M.data[0].i,M.data[0].j,M.data[0].e);
printf("(%d,%d,%g)\t",M.data[1].i,M.data[1].j,M.data[1].e);
printf("(%d,%d,%g)\n",M.data[2].i,M.data[2].j,M.data[2].e);
//***************************************************************************
//打印原始矩阵
//***************************************************************************
printf("COO,打印原始矩阵如下:\n");
for (i = 0; i<M.mu; i++)
{
for (j = 0; j<M.nu; j++)
{
int bs = 0;
for(t = 0;t<M.tu;t++)
{
if(i == M.data[t].i && j == M.data[t].j){
printf("%g\t",M.data[t].e);
bs = 1;
break;
}
}
if(bs == 0){
printf("0\t");
}
}
putchar('\n');//每行结束换行
}
//***************************************************************************
//矩阵转置
//***************************************************************************
Tr.mu = M.nu;
Tr.nu = M.mu;
Tr.tu = M.tu;
for(t = 0;t<M.tu;t++)
{
Tr.data[t].i = M.data[t].j;
Tr.data[t].j = M.data[t].i;
Tr.data[t].e = M.data[t].e;
}
//***************************************************************************
//打印转置矩阵
//***************************************************************************
printf("COO,打印转置矩阵如下:\n");
for (i = 0; i<Tr.mu; i++)
{
for (j = 0; j<Tr.nu; j++)
{
int bs = 0;
for(t = 0;t<Tr.tu;t++)
{
if(i == Tr.data[t].i && j == Tr.data[t].j){
printf("%g\t",Tr.data[t].e);
bs = 1;
break;
}
}
if(bs == 0){
printf("0\t");
}
}
putchar('\n');//每行结束换行
}
//***************************************************************************
//以 CSR格式存儲 Xs
//***************************************************************************
Xs.mu = m;
Xs.nu = n;
int num = 0;
for (i = 0; i<m; i++)
{
Xs.dist[i].l = num;
for (j = 0; j<n; j++)
{
if(!(sp[i][j]<0.000001&&sp[i][j]>-0.000001))
{
Xs.data[num].j = j;
Xs.data[num].e = sp[i][j];
num = num + 1;
}
}
}
Xs.dist[m].l = num;
Xs.tu = num;
//***************************************************************************
//打印三個向量
//***************************************************************************
//方式一,先计算出三个,再打印
//方式二,一直打印,累计三个
printf("CSR,打印三个向量:\n");
int js = 0;
for(i=1;i<=m;i++)
{
if(js>=3)
{
break;
}
for(j=0;j<Xs.dist[i].l-Xs.dist[i-1].l;j++)
{
if(js>=3)
{
break;
}
printf("(%d,%d,%g)\t",Xs.dist[i-1].l,Xs.data[Xs.dist[i-1].l+j].j,Xs.data[Xs.dist[i-1].l+j].e);
js = js + 1;
}
}
//***************************************************************************
//打印原始矩陣
//***************************************************************************
printf("\nCSR,打印原始矩阵如下:\n");
for (i = 0; i<Xs.mu; i++)
{
if(Xs.dist[i+1].l-Xs.dist[i].l>0)
{
for(j = 0; j<Xs.nu; j++)
{
int bs = 0;
for(t = Xs.dist[i].l;t<Xs.dist[i+1].l;t++)
{
if(j == Xs.data[t].j){
printf("%g\t",Xs.data[t].e);
bs = 1;
break;
}
}
if(bs == 0){
printf("0\t");
}
}
} else {
for(j = 0; j<Xs.nu; j++)
{
printf("0\t");
}
}
putchar('\n');//每行结束换行
}
//***************************************************************************
//矩陣转置 XsZ
//***************************************************************************
XsZ.mu = Xs.nu;
XsZ.nu = Xs.mu;
XsZ.tu = Xs.tu;
int Znum = 0;
for(i=0;i<XsZ.nu;i++)
{
XsZ.dist[i].l = Znum;
for(j=0;j<XsZ.tu;j++)
{
if(i == Xs.data[j].j)
{
XsZ.data[Znum].e = Xs.data[j].e;
for(t=0;t<Xs.mu;t++){
if(j>=Xs.dist[t].l&&j<=Xs.dist[t+1].l){
XsZ.data[Znum].j = t;
}
}
Znum = Znum + 1;
}
}
}
XsZ.dist[XsZ.nu].l = Znum;
//***************************************************************************
//打印转置矩阵
//***************************************************************************
printf("CSR,打印转置矩阵如下:\n");
for (i = 0; i<XsZ.mu; i++)
{
if(XsZ.dist[i+1].l-XsZ.dist[i].l>0)
{
for(j = 0; j<XsZ.nu; j++)
{
int bs = 0;
for(t = XsZ.dist[i].l;t<XsZ.dist[i+1].l;t++)
{
if(j == XsZ.data[t].j){
printf("%g\t",XsZ.data[t].e);
bs = 1;
break;
}
}
if(bs == 0){
printf("0\t");
}
}
} else {
for(j = 0; j<Xs.nu; j++)
{
printf("0\t");
}
}
putchar('\n');//每行结束换行
}
system("pause");//运行结果停留显示,不会一闪而过
}
input.bat文件内容示例如下:
15
15
0 2.8 0 0 0 0 0 0 0 0 0 0 0 0 0
-4.3 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3
0 0 0 0 0 0 8 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 3.5 0 0 0 86 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 4 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 7 0 0 0 0 0 0 0 0 0 0 5 0 0
0 0 0 3 0 0 23 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 6 0 0 0 0 1.1 0 0 0
9 0 0 0 0 0 0 0 2 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -8.52