【问题标题】:Multidimensional Array Patterned Access多维阵列模式访问
【发布时间】:2014-05-04 01:58:54
【问题描述】:

所以我有一个 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 多维数组,所以查找表会太大。

【问题讨论】:

  • 好问题。您的256 x 4096 多维数组是否也包含4 x 4s?
  • 不,它将由 256x256 组成 :)

标签: c algorithm math multidimensional-array output


【解决方案1】:

鉴于您的模式具有许多美丽的对称性,您可以选择像有意识构造的成果一样的结果:

kth 块中jth 列的ith 行中的元素是(4*i+5*j)%16+16*kijk 都在范围 [0 ,3])。

您希望在输出中看到的nth 组由 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 的任何环境。 编辑: 它编译得很好并产生所需的输出。

【讨论】:

  • 谢谢,我不知道。我尝试了代码,它在in 在上一行声明后工作。
  • 能否粘贴整个代码段并解释复杂的表达式?
  • 唯一复杂的表达式是行坐标,它的计算是基于这样一个事实,即n 组使用[w*k, (w+1)*k-1] 范围内的行索引,对于这样的kn 是在那个范围内。此外,第一个元素的行坐标正好是n,从那以后,每个元素的行坐标都小1,直到到达范围的下边界。在这种情况下,我们从上边界继续。
【解决方案2】:

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 次。

【讨论】:

  • 这似乎可行,但你能解释一下 überlong 的计算吗?
  • 我已经更新了我的解决方案。也许现在更清楚了。
【解决方案3】:

让我们稍微观察一下您的小组。一个值得注意的事实;每个组都以 [row, 0] 开始。第二个事实,组中的每个后续元素都尝试 1-up 1-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 256s 上使用它,这将有效,彼此叠放。

编辑

如果你对分支不满意,就像你似乎对你的评论一样,那么使用下面的赋值来代替上面的三元赋值:

...
m = ( m + w - 1 ) % w + x / w * w;
...

上面的东西强加了一个带有偏移量的模运算x / w * w

在数学中,在 ( mod w ) 下,m - 1m - 1 + w 将描述相同的值。事实上,你可以任意数量的ws,它们都会崩溃。

问题是,在 C 中,% 不是模运算符,而是余数运算符。因此,如果m == 0(在第一个块中发生w-很多次)(m - 1) % w; 将是负数,并且不会高于w - 1

所以,我在数学中使用了模运算符身份,我已经在上面描述过。

x / w * w 仅用于偏移量。 ... / w * wx 降到最接近 w 的倍数。

如果您肯定要使用 2 的幂次方的维度,那么您可以使用 (x &amp; ~(w - 1)),这也会使 x 下降到最接近的任何 w 的倍数,即 2 的幂次方。像这样:

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

&amp;ing 将清除那些带有0s 的位,用于&amp;ee。结果将是 &amp;ee 减少到最接近的 256 倍数。

【讨论】:

  • 有没有办法使用模而不是分支?
  • @haneefmubarak 好吧,当然,因为最后,我们所做的是带有偏移量的模运算。请改用m = ( m + w - 1 ) % w + x * w; 赋值。如果你看不出它为什么起作用,别担心,我会解释的。
  • @haneefmubarak 抱歉,显然我在这里写错了偏移量。应该是... x / w * w;,而不是直接... x * w;
  • @haneefmubarak 哦,好吧,即使没有你的两个变量 mn,elias 显然已经给出了这个解决方案。它看起来有点晦涩,但无论如何
【解决方案4】:

我不确定您要查找的确切输出,但您可以获得以下输出:

 [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");

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-24
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 2018-04-14
    • 1970-01-01
    相关资源
    最近更新 更多