欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

稀疏矩阵

程序员文章站 2022-07-04 10:22:16
...

C++ 矩阵操作

假设我们需要操作一个 N*M 的矩阵。为了简单,我们使用 int 类型进行说明。在实际编码中,肯定是需要使用 STL template。

矩阵的存储

静态存储

const int MAXN=1e5;    //定义矩阵最大行数
const int MAXM=1e5;    //定义矩阵最大列数
int array[MAXN][MAXM]; //定义矩阵

使用指针

使用指针包括两部分代码。一部分是内存申请,另外一部分是内存释放。

内存申请

int **array;//指向指针的指针,表示一个二维数组
array=new int *[n];//申请行
for (int i=0; i<n; i++) {
    array[i]=new int[m];//申请列
}

内存释放

for (int i=0; i<n; i++) {
    delete[] array[i];//释放列
}
delete[] array;//释放行

使用 STL 的 vector

vector<vector<int> > array(m); //这个m一定不能少

空间复杂度

从上面的 C++ 代码,我们可以非常明显的知道,矩阵的空间复杂度为 O(N*M),也就是 O(N^2)。

矩阵的遍历

我们知道一个 N*M 的矩阵,如果使用最基础的 C++ 程序实现,就是一个两重循环的遍历。代码如下

for (int i=0; i<n; i++) {
    for (int j=0; j<m; j++) {
        cout<<array[i][j];
    }
}

时间复杂度

从上面的 C++ 代码,我们可以非常明显的知道,矩阵的时间复杂度为 O(N*M),也就是 O(N^2)。

稀疏矩阵定义

在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵。如下图所示的 15*15 矩阵就是稀疏矩阵。

稀疏矩阵

为什么要研究稀疏矩阵

从上面的内容,我们可以看到,一个满阵,它的时间复杂度和空间复杂度都是非常大的。尤其在数学研究的时候,维度 N 可能会趋向无穷大。

大型稀疏矩阵在计算科学以及工程应用中往往应用于求解 PDE(偏微分方程)。

因此,研究稀疏矩阵是数值计算,科学搬砖中必不可少的内容。其实这是一个造*的过程,只是为了加深对矩阵的理解。

稀疏矩阵存储

由于稀疏矩阵的特性,我们不需要使用满阵进行存储。

Coordinate Format(COO)

COO 是一种坐标形式的稀疏矩阵。采用三个数组 row、col 和 data 保存非零元素的信息,这三个数组的长度相同。row 数组保存元素的行,col 数组保存元素的列,data 数组保存元素的值。

存储的主要优点是灵活、简单,仅存储非零元素以及每个非零元素的坐标。但是 COO 不支持元素的存取和增删,一旦创建之后,除了将之转换成其它格式的矩阵,几乎无法对其做任何操作和矩阵运算。

稀疏矩阵

对应的 C++ 代码如下:

int row[] ={0, 0, 1, 1, 2, 2, 2, 3, 3};
int col[] ={0, 1, 1, 2, 0, 2, 3, 1, 3};
int data[]={1, 7, 2, 8, 5, 3, 9, 6, 4};

我们可以看到 COO 在保存的列中有重复,还不是最节约的方式。

稀疏矩阵

Compressed Sparse Row Format(CSR)

行压缩,是按行存储一个稀疏矩阵的方式。需要三类数据来表达:数值,列号,以及行偏移。CSR 不是三元组,而是整体的编码方式。数值和列号与 COO 一致,表示一个元素以及其列号,行偏移表示某一行的第一个元素在 values 里面的起始偏移位置。

稀疏矩阵

如上图中,第一行元素 1 是 0 偏移,第二行元素 2 是 2 偏移,第三行元素 5 是 4 偏移,第 4 行元素 6 是 7 偏移。在行偏移的最后补上矩阵总的元素个数,本例中是 9。

和 COO 相比,我们通过行压缩,节约了存储空间。

对应的 C++ 代码如下:

int row[] ={0, 2, 4, 7, 9};
int col[] ={0, 1, 1, 2, 0, 2, 3, 1, 3};
int data[]={1, 7, 2, 8, 5, 3, 9, 6, 4};

稀疏矩阵

Compressed Sparse Column Format(CSC)

列压缩,是按列存储一个稀疏矩阵的方式。需要三类数据来表达:数值,行号,以及列偏移。CSC 不是三元组,而是整体的编码方式。数值和行号与 COO 一致,表示一个元素以及其行号,列偏移表示某一列的第一个元素在 values 里面的起始偏移位置。

稀疏矩阵

如上图中,第一列元素 1 是 0 偏移,第二列元素 7 是 2 偏移,第三列元素 8 是 5 偏移,第 4 列元素 9 是 7 偏移。在列偏移的最后补上矩阵总的元素个数,本例中是 9。

和 COO 相比,我们通过列压缩,节约了存储空间。

对应的 C++ 代码如下:

int row[] ={0, 0, 1, 1, 2, 2, 2, 3, 3};
int col[] ={0, 2, 5, 7, 9};
int data[]={1, 5, 7, 2, 6, 8, 3, 9, 4};

稀疏矩阵

总结

COO、CSR 和 CSC 三种方法各有用途,我们使用 CSR 最多,因为在大部分科学计算中,基本都是运行 Ax=b 这个问题。

下一步工作

将稀疏矩阵存储原理部分解释完成后,下面将开始造*的过程。也就是自己写一个稀疏矩阵的类,用于保存。将来在这个基础上,进一步扩充代码。逐步完成矩阵运算。

整个造*的过程,相关的代码都会保存在 Github 中,https://github.com/zhouyium/SparseMatrix.git