Published on

列主序 vs 行主序:内存布局详解

用 2×2 矩阵清晰地解释列主序行主序的区别。

矩阵定义

我们先定义一个 2×2 矩阵:

矩阵元素:
a00  a01
a10  a11

其中第一个下标是行索引,第二个下标是列索引


1. 行主序(Row-Major Order)

C/C++、Python等语言的默认存储方式

内存布局

内存地址: 0     1     2     3
存储元素: a00   a01   a10   a11

访问公式

index = i * cols + j
// 其中:
// i = 行索引 (0,1)
// j = 列索引 (0,1)
// cols = 矩阵的列数 (2)

计算示例

a00: i=0, j=00*2 + 0 = 0
a01: i=0, j=10*2 + 1 = 1
a10: i=1, j=01*2 + 0 = 2
a11: i=1, j=11*2 + 1 = 3

可视化存储

内存: | a00 | a01 | a10 | a11 |
逻辑: [0]0结束 [1]1结束

特征:同一行的元素在内存中相邻存储。


2. 列主序(Column-Major Order)

Fortran、MATLAB、BLAS/LAPACK库的默认存储方式

内存布局

内存地址: 0     1     2     3
存储元素: a00   a10   a01   a11

访问公式

index = j * rows + i
// 其中:
// i = 行索引 (0,1)
// j = 列索引 (0,1)
// rows = 矩阵的行数 (2)

这正是你提供的宏定义:

#define IDX2C(i,j,ld) (((j)*(ld))+(i))  // ld = leading dimension = rows

计算示例

a00: i=0, j=00*2 + 0 = 0
a10: i=1, j=00*2 + 1 = 1
a01: i=0, j=11*2 + 0 = 2
a11: i=1, j=11*2 + 1 = 3

可视化存储

内存: | a00 | a10 | a01 | a11 |
逻辑: [0]0结束 [1]1结束

特征:同一列的元素在内存中相邻存储。


3. 对比表格

特性行主序 (Row-Major)列主序 (Column-Major)
默认语言C, C++, PythonFortran, MATLAB
内存布局逐行存储逐列存储
公式i*cols + jj*rows + i
连续元素同一行同一列
遍历优化内循环用列索引内循环用行索引

4. 遍历性能影响

行主序优化遍历:

// 行主序:内循环应该是列索引
for (int i = 0; i < 2; i++) {      // 行
    for (int j = 0; j < 2; j++) {  // 列(内循环)
        // 连续访问内存:a00→a01→a10→a11
        value = matrix[i*2 + j];  // 行主序公式
    }
}

列主序优化遍历:

// 列主序:内循环应该是行索引
for (int j = 0; j < 2; j++) {      // 列
    for (int i = 0; i < 2; i++) {  // 行(内循环)
        // 连续访问内存:a00→a10→a01→a11
        value = matrix[j*2 + i];  // 列主序公式
    }
}

5. 实际数值示例

假设矩阵:

1.0  2.0
3.0  4.0

行主序内存:

地址: 0    1    2    3
数值: 1.0  2.0  3.0  4.0
      a00  a01  a10  a11

列主序内存:

地址: 0    1    2    3
数值: 1.0  3.0  2.0  4.0
      a00  a10  a01  a11

关键记忆点

  1. 行主序:先存完一整行,再存下一行
  2. 列主序:先存完一整列,再存下一列
  3. 你的宏 IDX2C(i,j,ld)列主序计算公式
  4. 性能优化的关键是让内循环访问连续内存

THE END