Appearance
题目
某 C 语言程序段如下:
c
for (i = 0; i <= 9; i++) {
temp = 1;
for (j = 0; j <= i; j++) {
temp *= a[j];
}
sum += temp;
}下列关于数组 a 的访问局部性的描述中,正确的是( )。
错因
B
只看了最内层 j 循环——内层一次只读 a[0..i] 一遍,没注意到外层 i 也是循环。这样会得出"每个元素只访问一次 = 无时间局部性"的结论。但外层 i 一直在变大,每次重新让 j 从 0 跑到 i,所以 a[0]、a[1]、…… 这些元素在不同的外层迭代中反复被访问——时间局部性显然存在。
C
把空间局部性和时间局部性的定义弄反了。或者认为"按下标 j 顺序访问连续地址"的程序"看上去太有规律,反而像不局部"——这是误解。空间局部性的定义就是"刚访问过的地址附近的地址也将被访问",按下标顺序遍历数组是经典的空间局部性场景。
D
可能直觉认为"循环里没有重复访问同一变量、又没有相邻访问"——但这两点本题都满足。或者完全没记住局部性定义,凭感觉乱选。这是排除前三项后唯一的剩项,掉进 D 通常意味着对两个概念都不熟。
总解析
两种局部性的定义(必须先记牢):
| 类型 | 定义 | 典型场景 |
|---|---|---|
| 时间局部性 | 刚刚访问过的存储位置,短时间内再次被访问 | 循环变量、计数器、被多次累加的数 |
| 空间局部性 | 刚刚访问过的位置附近的位置,短时间内被访问 | 顺序遍历数组、指令流(PC+4) |
第一步:模拟外层 i 的几轮,看 a[j] 的访问轨迹
| i | j 取值范围 | 访问的 a[j] 序列 |
|---|---|---|
| 0 | 0 | a[0] |
| 1 | 0, 1 | a[0], a[1] |
| 2 | 0, 1, 2 | a[0], a[1], a[2] |
| 3 | 0, 1, 2, 3 | a[0], a[1], a[2], a[3] |
| ... | ... | ... |
| 9 | 0~9 | a[0], a[1], ..., a[9] |
总访问次数: 次访问,但只涉及 10 个不同元素。
第二步:判断时间局部性
a[0] 一共被访问 10 次(每个 i 都访问),a[1] 被访问 9 次,……同一个元素短时间内反复被访问 → 有时间局部性 ✓。
第三步:判断空间局部性
每轮内层 j 循环按 0、1、2、… 顺序访问 a[j]——访问 a[0] 后接着访问 a[1],地址连续。数组在内存里也是连续存放,相邻元素地址相邻 → 有空间局部性 ✓。
结论:两种局部性都满足。
最终答案是 A(时间局部性和空间局部性皆有)。
判定速查:
| 程序模式 | 时间局部性 | 空间局部性 |
|---|---|---|
| 顺序遍历数组(仅 1 遍) | 弱 | 有 |
| 顺序遍历数组(多遍) | 有 | 有 |
| 跳跃访问(如 a[0], a[100], a[200]) | 弱 | 无 |
| 频繁读写同一变量(counter) | 有 | 弱 |
| 本题(外层 i 重复,内层 j 顺序) | 有 | 有 |