You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何编写压缩稀疏行(CSR)格式矩阵的转置算法?

如何实现CSR格式稀疏矩阵的转置算法

嘿,这个问题问得特别实在——CSR(压缩稀疏行)转置是稀疏矩阵操作里的核心基础,我来给你拆解一套清晰的实现思路,从原理到步骤再到注意点都讲明白。

首先先快速回顾下CSR的结构,毕竟转置的前提是吃透原格式:

CSR格式用三个一维数组存储m×n的稀疏矩阵:

  • values:按行顺序存储所有非零元素的值
  • col_indices:对应values中每个元素的列索引
  • row_ptr:长度为m+1,其中row_ptr[i]表示第i行第一个非零元素在values中的起始下标,row_ptr[m]等于总非零元素个数

接下来分两种思路讲,先从最容易理解的朴素实现入手,再提优化方向:

一、朴素转置算法(适合理解原理)

这个方法分三步走,核心是先统计转置后每行的非零元素数量,再填充数据:

步骤1:统计转置后每行的非零元素个数

转置后的矩阵A'的第i行,对应原矩阵A的第i列。所以我们需要统计原矩阵每一列的非零元素数量:

  • 创建一个长度为n(原矩阵列数)的计数数组count,初始化为0
  • 遍历原矩阵的col_indices数组,对每个列索引c,执行count[c] += 1

步骤2:构建转置后的row_ptr_T数组

row_ptr_T是转置矩阵的行指针数组,长度为n+1:

  • row_ptr_T[0] = 0
  • 对i从1到n,执行row_ptr_T[i] = row_ptr_T[i-1] + count[i-1]
  • 最后row_ptr_T[n]会等于总非零元素个数,和原矩阵的row_ptr[m]一致

步骤3:填充转置后的values_Tcol_indices_T

这里需要一个临时数组pos来跟踪转置后每行当前填充的位置,初始值等于row_ptr_T

  • 遍历原矩阵的每一行j(从0到m-1):
    • 找到该行非零元素在values中的起始和结束下标:start = row_ptr[j]end = row_ptr[j+1]
    • 对k从start到end-1:
      • 取当前元素的列索引c = col_indices[k],值v = values[k]
      • 转置后,这个元素属于A'的第c行,位置是pos[c]
      • 执行:
        values_T[pos[c]] = v
        col_indices_T[pos[c]] = j  # 原行索引变转置后的列索引
        pos[c] += 1
        

举个直观的例子帮你理解:
原3×3矩阵A:

1 0 2
0 3 0
4 5 6

对应的CSR数组:

  • values = [1, 2, 3, 4, 5, 6]
  • col_indices = [0, 2, 1, 0, 1, 2]
  • row_ptr = [0, 2, 3, 6]

按步骤执行后,转置矩阵A'的CSR数组会是:

  • values_T = [1, 4, 3, 5, 2, 6]
  • col_indices_T = [0, 2, 1, 2, 0, 2]
  • row_ptr_T = [0, 2, 4, 6]
    完全对应A'的结构:
1 0 4
0 3 5
2 0 6

二、优化方向(针对大型稀疏矩阵)

如果处理的是超大规模的稀疏矩阵,朴素方法的效率可以进一步提升:

  • 并行计数:统计count数组的步骤可以并行化,因为每个列的计数相互独立
  • 避免临时数组:有些实现会直接在row_ptr_T上修改来跟踪位置,减少内存开销
  • 原地转置:如果内存受限,可以研究原地转置的算法,但实现复杂度会高很多,一般不推荐除非特殊场景

关键注意事项

  • 数组大小要匹配:转置后values_Tcol_indices_T的长度等于原矩阵总非零数,row_ptr_T长度是n+1(n是原矩阵列数)
  • 索引边界:注意原矩阵的行/列索引是从0开始还是1开始,不同实现可能有差异,要保持一致性
  • 空矩阵处理:如果原矩阵没有非零元素,直接返回空的CSR数组即可

内容的提问来源于stack exchange,提问作者qwers

火山引擎 最新活动