所以我有一个 4x16 的多维数组。我需要在 4x4 部分中按特定顺序访问它:
数组:
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
交通路线:
1.
[00]
[03]
[02]
[01]
2.
[05]
[04]
[07]
[06]
3.
[10]
[09]
[08]
[11]
4.
[15]
[14]
[13]
[12]
5.
Repeat for next 4x4 block
生成的访问模式:
[00][05][10][15]
[04][09][14][03]
[08][13][02][07]
[12][01][06][11]
[16][21][26][31]
[20][25][30][19]
[24][29][18][23]
[28][17][22][27]
[32][37][42][47]
[36][41][46][35]
[40][45][34][39]
[44][33][38][43]
[48][53][58][63]
[52][57][62][51]
[56][61][50][55]
[60][49][54][59]
现在,我也想以四个点为一组访问这些,如上所示,我也想事先看看会访问什么,所以我写了这个:
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
void main (void) {
int m;
int n;
const int h = 16;
const int w = 4;
int skip;
int x, y;
// ABCD
// BCDA
// CDAB
// DABC
// ABCD
// 0 => [0,0][3,1][2,2][1,3]
// 1 => [1,0][0,1][3,2][2,3]
// 2 => [2,0][
for (x = 0; x < h; x++) {
for (y = 0; y < w; y++) {
m = w - ((x + y) % w);
n = x + m;
printf ("[%i,%i]", ((x + y)), n);
}
printf ("n");
}
return;
}
当它运行时,我想得到以下输出:
[r,c][r,c][r,c][r,c] (Group 0)
[r,c][r,c][r,c][r,c] (Group 1)
...
前任:
组 0 和 1
[0,0][3,1][2,2][1,3]
[1,0][0,1][3,2][2,3]
。
组 5 和 6
[5,0][4,1][7,2][6,3]
[6,0][5,1][4,2][7,3]
等等。
但是,我得到的输出是:
[0,4][1,3][2,2][3,1]
[1,4][2,3][3,2][4,5]
[2,4][3,3][4,6][5,5]
[3,4][4,7][5,6][6,5]
[4,8][5,7][6,6][7,5]
[5,8][6,7][7,6][8,9]
[6,8][7,7][8,10][9,9]
[7,8][8,11][9,10][10,9]
[8,12][9,11][10,10][11,9]
[9,12][10,11][11,10][12,13]
[10,12][11,11][12,14][13,13]
[11,12][12,15][13,14][14,13]
[12,16][13,15][14,14][15,13]
[13,16][14,15][15,14][16,17]
[14,16][15,15][16,18][17,17]
[15,16][16,19][17,18][18,17]
如何获取上述输出?
注意:
我知道我可以使用查找表,但之后我将将其扩展到 256x4096 多维数组,因此查找表太大了。
GCC 4.8.2: gcc -Wall -Wextra main.c:
#include <stdio.h>
int main() {
const int w = 4; // 256
int i = 0;
for (i = 0; i < w * w * 4 ; ++i) { // 16
// Column calculation is trivial.
int c = i % w;
// Row calculation.
int section_offset = (w * (i / (w * w)));
int first_pass = ((w - i % w) % w);
int shift = i / w;
int r = (first_pass + shift) % w + section_offset;
printf("[%2i,%2i]", r, c);
if (!((i + 1) % w)) {
printf(" (Group %2i)n", i / w); } }
return 0; }
输出:
[ 0, 0][ 3, 1][ 2, 2][ 1, 3] (Group 0)
[ 1, 0][ 0, 1][ 3, 2][ 2, 3] (Group 1)
[ 2, 0][ 1, 1][ 0, 2][ 3, 3] (Group 2)
[ 3, 0][ 2, 1][ 1, 2][ 0, 3] (Group 3)
[ 4, 0][ 7, 1][ 6, 2][ 5, 3] (Group 4)
[ 5, 0][ 4, 1][ 7, 2][ 6, 3] (Group 5)
[ 6, 0][ 5, 1][ 4, 2][ 7, 3] (Group 6)
[ 7, 0][ 6, 1][ 5, 2][ 4, 3] (Group 7)
[ 8, 0][11, 1][10, 2][ 9, 3] (Group 8)
[ 9, 0][ 8, 1][11, 2][10, 3] (Group 9)
[10, 0][ 9, 1][ 8, 2][11, 3] (Group 10)
[11, 0][10, 1][ 9, 2][ 8, 3] (Group 11)
[12, 0][15, 1][14, 2][13, 3] (Group 12)
[13, 0][12, 1][15, 2][14, 3] (Group 13)
[14, 0][13, 1][12, 2][15, 3] (Group 14)
[15, 0][14, 1][13, 2][12, 3] (Group 15)
如果有的话,见解是(i + X) % N
旋转序列 [0..N-1],X 次。
我不确定您要查找的输出,但您可以获得以下输出:
[0, 0] [3, 1] [2, 2] [1, 3]
[1, 0] [0, 1] [3, 2] [2, 3]
[2, 0] [1, 1] [0, 2] [3, 3]
[3, 0] [2, 1] [1, 2] [0, 3]
[0, 0] [3, 1] [2, 2] [1, 3]
[1, 0] [0, 1] [3, 2] [2, 3]
[2, 0] [1, 1] [0, 2] [3, 3]
[3, 0] [2, 1] [1, 2] [0, 3]
[0, 0] [3, 1] [2, 2] [1, 3]
[1, 0] [0, 1] [3, 2] [2, 3]
[2, 0] [1, 1] [0, 2] [3, 3]
[3, 0] [2, 1] [1, 2] [0, 3]
[0, 0] [3, 1] [2, 2] [1, 3]
[1, 0] [0, 1] [3, 2] [2, 3]
[2, 0] [1, 1] [0, 2] [3, 3]
[3, 0] [2, 1] [1, 2] [0, 3]
通过使用此代码代替当前的 for 循环:
for (x = 0; x < h; x++) {
for (y = 0; y < w; y++) {
m = w - (x + w - 1 - (y % w)) % w - 1;
n = x;
printf ("[%i,%i]", m, n);
}
printf ("n");
}
让我们稍微观察一下你的小组。一个值得注意的事实;每组以 [行, 0] 开头。第二个事实,组中的每个后续元素都试图向 1-up-right。第三个事实,当它们撞到天花板时,它们会跌到底部。仅此而已:
- 从
[x, 0]
开始 - 不管怎么走,都走右边
- 如果我们不在天花板上,就往上走一个,否则往下走三个
放在你的循环中:
...
for ( x = 0; x < h; x++ ) {
m = x; // start off with [x, ...
n = 0; // ... 0]
for ( y = 0; y < w; y++ ) {
printf( "[%i,%i]", m, n );
m = ( m > x / w * w ) ? m - 1 : m + w - 1;
// if not at ceiling, decrease m by 1, else increase by 3
n++; // increase n regardless
}
printf( "n" );
}
...
我的问题无法得到答复,所以如果您需要比这更灵活的东西,我很抱歉。如果您要在 8 256 x 256
秒内使用它,将它们放在彼此之上,这将起作用。
编辑
如果您对分支不满意,就像您似乎对评论不满意一样,请使用以下赋值作为上述三元赋值的替代品:
...
m = ( m + w - 1 ) % w + x / w * w;
...
上面的东西强加了一个带有偏移x / w * w
的模运算。
数学中,在( mod w )
下,m - 1
和m - 1 + w
将描述相同的值。事实上,你可以随心所欲地w
,它们都会融化。
问题是,在 C 中,%
不是模运算符,而是余数运算符。因此,在m == 0
的情况下(在第一个块中w
多次发生(,(m - 1) % w;
将是负一,并且不会高于w - 1
。
因此,我在数学中使用了我上面描述的模运算符恒等式。
x / w * w
仅用于偏移量。 ... / w * w
将x
降低到最接近的w
倍数。
如果你肯定要使用 2 的幂的维度,那么你可以使用 (x & ~(w - 1))
,这也会使x
降低到任何 2 的幂w
的最接近倍数。喜欢这个:
m = ( m + w - 1 ) % w + (x & ~(w - 1));
它的工作原理是清除用于表示w
的单个位右侧的位。例如,对于w = 256
:
// bit representation of w
0000 ... 0001 0000 0000
// of w - 1
0000 ... 0000 1111 1111
// of ~(w - 1)
1111 ... 1111 0000 0000
&
这样做会清除这些位,&
ee的 0
s。结果将是&
ee减少到最接近的倍数256。
鉴于您的模式具有许多美丽的对称性,您可以像有意识构造的果实一样选择结果:
第 k
个块中第 j
列第 i
行中的元素是 (4*i+5*j)%16+16*k
(i
、j
和 k
都在 [0,3] 范围内(。
您希望在输出中看到的第 n
组由 4 对组成,(n/4*4+(n+4-i)%4, i)
i
再次处于 [0,3] 中。
const int h = 16;
const int w = 4;
int n,i;
for (n = 0; n < h; n++) {
for (i = 0; i < w; i++) {
printf ("[%i,%i]", (n/w)*w+(n+w-i)%w, i);
}
printf ("n");
}
抱歉,我不确定语法是否正确,我现在的机器上没有任何 c 环境。 编辑:它编译良好并产生所需的输出。