数据结构–稀疏矩阵转置(列序递增算法)的c语言实现(超详细注释/实验报告)
知识小回顾
稀疏矩阵是指矩阵中大多数元素为零的矩阵。从直观上讲,当非零元素个数低于总元素的30%时,这样的矩阵为稀疏矩阵。
稀疏矩阵的三元组表表示方法
对于稀疏矩阵的压缩存储,采取只存储非零元素的方法。由于系数矩阵中非零元素 a i j a_{ij} aij的分布没有规律,因此,在存储非零元素值的同时,还必须存储该非零元素在矩阵中所处的行号和列号的位置信息,这就是稀疏矩阵的三元组表表示方法。
实验题目
- 稀疏矩阵采用三元组顺序表的存储结构
- 能够实现按列序递增进行转置
- 输出矩阵转置前后的三元组
实验目的
- 了解压缩存储的基本原理
- 了解稀疏矩阵的三元组表的压缩存储方法
- 熟悉三元组表表示的稀疏矩阵运算的实现
实验要求
- 稀疏矩阵的三元组表示法及三元组表示的矩阵的转置的实现
- 三元组表示的稀疏矩阵相关运算的实现
实验内容和实验步骤
1.需求分析
实现用户输入一个三元组表,程序将其转置并输出。
2. 概要设计
设计一个函数实现转置操作,在主函数中让用户输入并输出结果。
3. 详细设计
导入库并定义三元组和三元组表的基本类型
#include<stdio.h>
#define MAXSIZE 20
typedef struct
{
int row,col,val;//非零元素的行下表和列下标以及值
}TriNode;
typedef struct
{
TriNode data[MAXSIZE+1];//非零元素的三元组表。data[0]未用
int m,n,len;//矩阵的行数、列数及非零元素个数
}TriTable;
稀疏矩阵列序递增转置的函数
//稀疏矩阵列序递增转置
void Transpose(TriTable A,TriTable *B)s
{
int i,j,k;
B->m=A.n;
B->n=A.m;
B->len=A.len;//行数、列数交换,长度还都是相等的
// printf("%d %d %d\n",B->m,B->n,B->len);
if(B->len>0)
{
j=1;//j为辅助计数器,记录转置后三元组在三元组B中的下标值
for(k=1;k<=A.n;k++)
{
for(i=1;i<=A.len;i++)
{
if(A.data[i].col==k)
{
B->data[j].col=A.data[i].row;
B->data[j].row=A.data[i].col;
B->data[j].val=A.data[i].val;
j++;
}
}
}
}
}
主函数部分
- 这里就是让用户输入需要转置的矩阵的相关信息,然后调用矩阵转置的函数,并输出转置后的矩阵。
int main()
{
TriTable s;
printf("请输入稀疏矩阵的行数、列数和非零元素个数(以空格隔开):");
// scanf("%d",&s.m);
// scanf("%d",&s.n);
// scanf("%d",&s.len);
scanf("%d%d%d",&s.m,&s.n,&s.len);
// printf("%d%d%d",s.m,s.n,s.len);
if(s.len==0)
return 0;
int val;
val=s.len;
int i;
for(i=1;i<=val;i++)
{
printf("第%d个元素<行号,列号,值>:",i);
scanf("%d%d%d",&s.data[i].row,&s.data[i].col,&s.data[i].val);
}
// printf("%d",s.data[2].val);
printf("转置前的三元组<行号,列号,值>:\n");
for(i=1;i<=s.len;i++)
{
printf("%d ,%d ,%d \n",s.data[i].row,s.data[i].col,s.data[i].val);
}
TriTable t;
Transpose(s,&t);
printf("转置后的三元组<行号,列号,值>:\n");
for(i=1;i<=t.len;i++)
{
printf("%d ,%d ,%d \n",t.data[i].row,t.data[i].col,t.data[i].val);
}
return 0;
}
4. 调试分析
遇到的问题及解决方法
- 一开始发现列数为矩阵最大列数的三元组无法转置,后来发现时条件判断中的<=误写成了<
算法的时空分析
算法已经实现了压缩存储,故空间复杂度相比于普通存储节省了不少。
算法的时间耗费主要是在双重循环中,其时间复杂度为
O
(
A
.
n
∗
A
.
l
e
n
)
O(A.n*A.len)
O(A.n∗A.len)。最坏情况是当矩阵中全部是非零元素时,这个时候时间复杂度为
O
(
A
.
m
∗
A
.
n
2
)
O(A.m*A.n^2)
O(A.m∗A.n2)若采用经典算法实现矩阵转置的算法时间复杂度为
O
(
A
.
m
∗
A
.
n
)
O(A.m*A.n)
O(A.m∗A.n)。因此,三元组表表示法
实验结果
实验指导中没有编写函数,我是结合课本和实验指导,写了一个转置的函数出来,这样使得程序的可移植性更强,并为后面编写一次定位快速转置做准备!
实验总结
顺序串需要注意的细节很多,多多重复,百炼成钢!
最后附上完整的代码
#include<stdio.h>
#define MAXSIZE 20
typedef struct
{
int row,col,val;//非零元素的行下表和列下标以及值
}TriNode;
typedef struct
{
TriNode data[MAXSIZE+1];//非零元素的三元组表。data[0]未用
int m,n,len;//矩阵的行数、列数及非零元素个数
}TriTable;
//稀疏矩阵列序递增转置
void Transpose(TriTable A,TriTable *B)s
{
int i,j,k;
B->m=A.n;
B->n=A.m;
B->len=A.len;//行数、列数交换,长度还都是相等的
// printf("%d %d %d\n",B->m,B->n,B->len);
if(B->len>0)
{
j=1;//j为辅助计数器,记录转置后三元组在三元组B中的下标值
for(k=1;k<=A.n;k++)
{
for(i=1;i<=A.len;i++)
{
if(A.data[i].col==k)
{
B->data[j].col=A.data[i].row;
B->data[j].row=A.data[i].col;
B->data[j].val=A.data[i].val;
j++;
}
}
}
}
}
int main()
{
TriTable s;
printf("请输入稀疏矩阵的行数、列数和非零元素个数(以空格隔开):");
// scanf("%d",&s.m);
// scanf("%d",&s.n);
// scanf("%d",&s.len);
scanf("%d%d%d",&s.m,&s.n,&s.len);
// printf("%d%d%d",s.m,s.n,s.len);
if(s.len==0)
return 0;
int val;
val=s.len;
int i;
for(i=1;i<=val;i++)
{
printf("第%d个元素<行号,列号,值>:",i);
scanf("%d%d%d",&s.data[i].row,&s.data[i].col,&s.data[i].val);
}
// printf("%d",s.data[2].val);
printf("转置前的三元组<行号,列号,值>:\n");
for(i=1;i<=s.len;i++)
{
printf("%d ,%d ,%d \n",s.data[i].row,s.data[i].col,s.data[i].val);
}
TriTable t;
Transpose(s,&t);
printf("转置后的三元组<行号,列号,值>:\n");
for(i=1;i<=t.len;i++)
{
printf("%d ,%d ,%d \n",t.data[i].row,t.data[i].col,t.data[i].val);
}
return 0;
}