稀疏矩阵

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

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值