如果我有一个2D数组,使用for循环遍历整个数组,行或列是微不足道的。但是,偶尔我需要遍历任意的2D子阵列。
一个很好的例子是数独,其中我可以将整个网格存储在2D数组中,但是然后需要分析每个单独的9个方块。目前,我会做以下事情:
for(i = 0; i < 9; i += 3) {
for(j = 0; j < 9; j += 3) {
for(k = 0; k < 3; k++) {
for(m = 0; m < 3; m++) {
block[m][k] == grid[j + m][i + k];
}
}
//At this point in each iteration of i/j we will have a 2D array in block
//which we can then iterate over using more for loops.
}
}
是否有更好的方法可以迭代任意子阵列,尤其是当它们以常规模式出现时,如上所述?
答案 0 :(得分:5)
这种循环结构的表现将是可怕的。考虑最内层的循环:
for(m = 0; m < 3; m++) {
block[m][k] == grid[j + m][i + k];
}
C是“row-major”有序,这意味着访问block
将导致每次迭代失效!那是因为没有连续访问内存。
grid
存在类似问题。您的嵌套循环顺序是在变更i
之前修复j
,但您正在访问grid
上的j
作为行。这又不是连续的,并且会在每次迭代时缓存未命中。
因此,处理嵌套循环和多维数组时的经验法则是将循环索引和数组索引放在相同的顺序中。对于你的代码,那是
for(j = 0; j < 9; j += 3) {
for(m = 0; m < 3; m++) {
for(i = 0; i < 9; i += 3) {
for(k = 0; k < 3; k++) {
block[m][k] == grid[j + m][i + k];
}
}
// make sure you access everything so that order doesn't change
// your program's semantics
}
}
答案 1 :(得分:0)
在数独的情况下你不能只存储9个3x3阵列。然后你不需要打扰子数组...如果你开始移动到比数独大得多的网格,你也可以通过这种方式提高缓存性能。
忽略这一点,上面的代码运行正常。
答案 2 :(得分:0)
想象一下你有一个2D数组a[n][m]
。要循环其右上角位于q x r
位置的子阵列x,y
,请使用:
for(int i = x; i < n && i < x + q; ++i)
for(int j = y; j < m && j < y + r; ++j)
{
///
}
对于您的数独示例,您可以执行此操作
for(int i = 0; i<3; ++i)
for(int j = 0; j < 3; ++j)
for(int locali = 0; locali < 3; ++locali)
for(int localj = 0; localkj <3; ++localj)
//the locali,localj element of the bigger i,j 3X3 square is
a[3*i + locali][3*j+localj]