- 学习目的
了解稀疏矩阵的特点和功能,掌握使用简单算法和快速转置算法进行三元组表存储的稀疏矩阵的转置,学会利用稀疏矩阵的转置处理一些具体问题。
- 要求
分别使用简单算法和快速转置算法进行三元组表存储的稀疏矩阵的转置,展示转置后的结果,了解这两种算法的时间复杂度和空间复杂度
- 概念介绍
稀疏矩阵是指在一个矩阵中,大部分元素为零的情况下,只存储非零元素及其对应的位置信息的一种特殊矩阵表示方式。由于在实际应用中,很多矩阵是稀疏的,采用稀疏矩阵的存储方式可以有效减少存储空间和计算复杂度。
稀疏矩阵通常使用三元组表(triplet list)来表示,也称为COO(Coordinate)格式。在三元组表中,每个非零元素都由一个三元组 (row, column, value) 表示,其中 row 和 column 分别表示非零元素所在的行和列的索引,value 表示该位置上的元素值。通过这种方式,可以避免存储大量的零元素,节省存储空间。
举例来说,对于一个 4x5 的稀疏矩阵:
可以使用三元组表表示为:
在实际应用中,稀疏矩阵的转置是一项常见的操作。通过转置,可以将矩阵的行变为列,列变为行,同时保持非零元素的位置和值不变。
转置稀疏矩阵的算法有多种,其中简单算法(Simple Transpose)是最直接的一种方法,它的时间复杂度为O(nz),其中 nz 表示非零元素的数量。简单算法的基本思想是遍历原矩阵的每个非零元素,将其转置后插入到新矩阵中的对应位置。
另一种常用的算法是快速转置算法(Fast Transpose),也称为COO格式转CSC或CSR格式。这种算法的时间复杂度为O(n + nz),其中 n 表示矩阵的维度。快速转置算法首先通过扫描原矩阵,统计每列(或每行)非零元素的个数,然后根据这些信息构建行偏移数组或列偏移数组,进而实现转置操作。
- 编写步骤和结果
实验步骤:
1.定义了稀疏矩阵的三元组节点类型和稀疏矩阵类型。
typedef struct {
int i, j;
int v;
} Triple; //三元组节点的类型
typedef struct {
Triple data[MaxSize];
int m, n, t; //行,列,表长
} TSMatrix; //稀疏矩阵类型
2.实现了稀疏矩阵转置的两种方法:简单转置和快速转置。
void TransposeTSMatrix(TSMatrix M, TSMatrix *T)
void FastTransposeTSMatrix(TSMatrix M, TSMatrix *T)
3.定义了打印稀疏矩阵的函数。
void printMatrix(TSMatrix M) {
for (int i = 0; i < M.t; ++i) {
printf("Position (%d, %d), Value: %d\n", M.data[i].i, M.data[i].j, M.data[i].v);
}
}
4. 在main函数中,创建了一个稀疏矩阵M,并初始化其行、列和表长以及节点的位置和值。
5. 打印M的原始矩阵。
6. 调用TransposeTSMatrix函数,将M简单转置后存储在矩阵T中,并打印转置后的矩阵T。
7. 调用FastTransposeTSMatrix函数,将M快速转置后存储在矩阵T中,并打印转置后的矩阵T。
结果:
图1.结果
- 容易出现的问题及解决方法
问题:在码主函数调用转置函数时出现语法错误导致不能正常运行
解决方法:混淆了实参和形参,在函数TransPoseTSMatrix中,使用&T是因为需要修改实参T的值,而不是仅仅修改它指向的地址中的值。如果使用TransposeTSMatrix(M, *T)或TransposeTSMatrix(M, T),则函数将会只修改函数内局部变量T的值,并不会对实参产生任何影响。为了让函数中的修改能够被主函数所感知,我们需要使用指向T的指针&T来将函数中处理后的结果返回给主函数。
- 总结及体会
在区分并掌握稀疏矩阵转置的两种算法的基础上,还要加强基础语法的理解,不然在语法方面会出现许多细微差错,进而导致整个函数运行有问题。
- 代码部分
#include<stdio.h>
#define MaxSize 10000
typedef struct {
int i, j;
int v;
} Triple; //三元组节点的类型
typedef struct {
Triple data[MaxSize];
int m, n, t; //行,列,表长
} TSMatrix; //稀疏矩阵类型
void TransposeTSMatrix(TSMatrix M, TSMatrix *T) {
T->m = M.n;
T->n = M.m;
T->t = M.t;
int q=0;
if (T->t) {
for (int col = 0; col < M.n; ++col) {
for (int p = 0; p < M.t; ++p) {
if (M.data[p].j == col) {
T->data[q].i = M.data[p].j;
T->data[q].j = M.data[p].i;
T->data[q].v = M.data[p].v;
q++;
}
}
}
}
}
void FastTransposeTSMatrix(TSMatrix M, TSMatrix *T) {
T->m = M.n;
T->n = M.m;
T->t = M.t;
if (T->t) {
int num[MaxSize], cpot[MaxSize]; //定义了M和T的最大容量
for (int col = 0; col < M.n; ++col) {
num[col] = 0;
}
for (int t = 0; t < M.t; ++t) {
++num[M.data[t].j];
}
cpot[0] = 0;
for (int col = 1; col < M.n; ++col) {
cpot[col] = cpot[col - 1] + num[col - 1];
}
for (int p = 0; p < M.t; ++p) {
int col = M.data[p].j;
int q = cpot[col];
T->data[q].i = M.data[p].j;
T->data[q].j = M.data[p].i;
T->data[q].v= M.data[p].v;
++cpot[col];
}
}
}
void printMatrix(TSMatrix M) {
for (int i = 0; i < M.t; ++i) {
printf("Position (%d, %d), Value: %d\n", M.data[i].i, M.data[i].j, M.data[i].v);
}
}
int main() {
TSMatrix M,T;
M.m=4;
M.n=5;
M.t=6;
M.data[0].i=0;M.data[0].j=1;M.data[0].v=5;
M.data[1].i=0;M.data[1].j=4;M.data[1].v=8;
M.data[2].i=1;M.data[2].j=0;M.data[2].v=1;
M.data[3].i=1;M.data[3].j=2;M.data[3].v=3;
M.data[4].i=2;M.data[4].j=1;M.data[4].v=-2;
M.data[5].i=3;M.data[5].j=0;M.data[5].v=6;
printf("Original Matrix:\n");
printMatrix(M);
TransposeTSMatrix(M, &T);
printf("\nTransposed Matrix (Simple):\n");
printMatrix(T);
FastTransposeTSMatrix(M, &T);
printf("\nTransposed Matrix (Fast ):\n");
printMatrix(T);
return 0;
return 0;
}