多维数组的存储

1417 字
7 分钟
多维数组的存储
Warning

含AI生成内容

多维数组的存储#

为什么数组在”栈、队列和数组”这一章#

408 大纲把数组放在第三章,核心原因是:这一章讲的是”线性表怎么落到内存上”。

  • 栈:限制只能在一端进出,落到内存上是数组或链表
  • 队列:限制只能一端进、另一端出,落到内存上是数组(含循环)或链表
  • 数组:定义本身就规定了”按下标随机访问、元素按某种顺序连续存储”——内存映射规则是整章最底层的一块拼图

数组这一节的核心不是”什么是数组”(你已经会了),而是 “二维及以上的数组,怎么按线性顺序排进一维内存里”


一维数组#

地址公式#

一维数组 A[0..n-1],每个元素占 LL 字节,首地址为 Addr(A[0])\text{Addr}(A[0])

Addr(A[i])=Addr(A[0])+iL\boxed{\text{Addr}(A[i]) = \text{Addr}(A[0]) + i \cdot L}

base 陷阱(⭐选择题高频)#

  • 0-based(C 语言):ii 直接使用
  • 1-based(数学记号如 A[1..n]A[1..n]):ii 替换为 i1i-1

408 大题 C 语言相关的代码一律 0-based;考研题面如果出现 A[1..n]A[1..n]mi,j(1i,jn)m_{i,j} (1 \leq i,j \leq n) 这种写法,是在用数学记号 1-based。两个 base 是题面给出的,不是你能选的——你要做的是把题目的 base 翻译到公式里。


二维数组#

二维数组 A[m][n]mmnn 列)需要把一个矩阵塞进一维内存里。

行优先(Row-major)#

一行一行按顺序排。C 语言和 Java 默认用这种。

A[0][0] A[0][1] ... A[0][n-1] A[1][0] A[1][1] ... A[1][n-1] ... A[m-1][n-1]
└──────── 第 0 行 n 个元素 ────┘└──────── 第 1 行 n 个元素 ────┘

地址公式(0-based)

Addr(A[i][j])=Addr(A[0][0])+(in+j)L\boxed{\text{Addr}(A[i][j]) = \text{Addr}(A[0][0]) + (i \cdot n + j) \cdot L}

记忆口诀:“行 × 列宽 + 列”

列优先(Column-major)#

一列一列按顺序排。Fortran 和 MATLAB 默认用这种。

A[0][0] A[1][0] ... A[m-1][0] A[0][1] A[1][1] ... A[m-1][1] ... A[m-1][n-1]
└──────── 第 0 列 m 个元素 ────┘└──────── 第 1 列 m 个元素 ────┘

地址公式(0-based)

Addr(A[i][j])=Addr(A[0][0])+(jm+i)L\boxed{\text{Addr}(A[i][j]) = \text{Addr}(A[0][0]) + (j \cdot m + i) \cdot L}

记忆口诀:“列 × 行高 + 行”

对偶性:行优先和列优先的公式是完全对偶的——把 iji \leftrightarrow jmnm \leftrightarrow n 同时交换就能从一个变成另一个。不要分开记两个公式,理解了对偶性以后只需要记一个。

1-based 形式#

如果题目用数学记号 mi,j(1im,1jn)m_{i,j} (1 \leq i \leq m, 1 \leq j \leq n)

Addr(mi,j)行优先=Addr(m1,1)+[(i1)n+(j1)]L\text{Addr}(m_{i,j})_{\text{行优先}} = \text{Addr}(m_{1,1}) + [(i-1) \cdot n + (j-1)] \cdot L

考场上不要去背 1-based 公式——把 0-based 公式记牢,再根据题目下标起点做平移,比硬记两套要稳。


反推每行列数题型(⭐必考题型)#

考研最爱的题型:题目不直接告诉你 n(每行列数),而是给两个元素的地址,让你先反推 n,再算第三个元素。

套路#

设按行优先存储,给定 Addr(A[i1][j1])=a1\text{Addr}(A[i_1][j_1]) = a_1Addr(A[i2][j2])=a2\text{Addr}(A[i_2][j_2]) = a_2

代入行优先公式两次相减,消掉 Addr(A[0][0])\text{Addr}(A[0][0])

a2a1=[(i2i1)n+(j2j1)]La_2 - a_1 = [(i_2 - i_1) \cdot n + (j_2 - j_1)] \cdot L

解出 nn

真题精讲:2021-03#

已知二维数组 A 按行优先方式存储,每个元素占用 1 个存储单元。若元素 A[0][0] 的存储地址是 100,A[3][3] 的存储地址是 220,则元素 A [5] [5] 的存储地址是?

第一步:用 A[3][3] 反推每行列数 n: 220=100+(3n+3)1220 = 100 + (3n + 3) \cdot 1 3n+3=120n=393n + 3 = 120 \Rightarrow n = 39

第二步:代入 A[5][5]: Addr(A[5][5])=100+(5×39+5)×1=100+195+5=300\text{Addr}(A[5][5]) = 100 + (5 \times 39 + 5) \times 1 = 100 + 195 + 5 = 300

答案 300

两个致命陷阱(⭐)#

陷阱 1:把 220100=120220 - 100 = 120 直接除以 3 得 n=40n = 40

A[3][3] 不仅在行方向跨了 3 行,列方向也跨了 3 列。必须写出完整方程 3n+3=1203n + 3 = 120 才能解出 n=39n = 39

陷阱 2:算到第 5 行的开头就停了

A[5][5] 不等于 A[5][0]。第 5 行开头偏移是 539=1955 \cdot 39 = 195还要再加 5 个列偏移 才到 A[5][5]。


三维及多维数组#

三维数组 A[d1][d2][d3]A[d_1][d_2][d_3](按行优先),A[i1][i2][i3]A[i_1][i_2][i_3] 之前的元素个数:

i1(d2d3)+i2d3+i3i_1 \cdot (d_2 \cdot d_3) + i_2 \cdot d_3 + i_3

记忆方法:从外层维度向内乘——第一维要跨过完整的 (d2×d3)(d_2 \times d_3) 个元素,第二维要跨过 d3d_3 个,第三维只移动 1 个。

推广到 n 维: offset(i1,i2,,in)=k=1nikp=k+1ndp\text{offset}(i_1, i_2, \ldots, i_n) = \sum_{k=1}^{n} i_k \cdot \prod_{p=k+1}^{n} d_p

考研一般不超过三维。行优先的本质就是最右边的下标变化最快,列优先反之。


判断使用哪种存储方式#

题目特征判断
题面明确写”按行优先”/“按列优先”直接用对应公式
给的是 C 语言数组 int A[m][n]行优先(C 默认)
出现 Fortran/MATLAB 字样列优先
完全没说一般按行优先(408 默认)

易错点汇总#

  1. 0-base / 1-base:看清题面,不要默认。C 代码题一定是 0-based
  2. 反推每行列数时方程必须完整a2a1=(i2i1)n+(j2j1)a_2 - a_1 = (i_2 - i_1) \cdot n + (j_2 - j_1),两项都不能丢
  3. 行偏移 + 列偏移都要加:算地址不要算到本行开头就停
  4. 行优先和列优先是对偶的:只记一个公式,另一个靠对偶变出来
  5. 元素占字节数 LL:题面会告诉你,不要默认是 1

考研高频考点#

  • ⭐ 行优先/列优先地址计算(选择题/填空题)
  • ⭐ 反推每行列数题型(选择题)
  • ⭐ base 陷阱(0-based vs 1-based)
  • 三维数组地址计算
  • 行优先 vs 列优先的本质区别(哪个下标变化最快)

关联页面#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

多维数组的存储
https://lingluoa.icu/posts/数据结构/array-storage/
作者
lingluoa
发布于
2026-07-04
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
lingluoa
Hello, I'm lingluoa.
公告
欢迎来到我的博客!不定期更新中。
文章目录
标签
站点统计
文章
53
分类
9
标签
75
总字数
175,771
运行时长
0
最后活动
0 天前
站点信息
构建平台
ESA Pages
博客版本
Firefly v6.15.6
文章许可
CC BY-NC-SA 4.0