将数组中的简单数据类型移动到特定位置的最快方法

时间:2015-11-03 06:02:44

标签: c++ c arrays performance

将已知大小的数组中的简单数据类型移动到特定位置的最快方法是什么?

我的具体情况是旋转存储为int [9]的游戏板 [0,1,2,3,4,5,6,7,8]变为[6,3,0,7,4,1,8,5,2]

在我的用例中,我有一个这些数组的向量,每个数组都需要旋转。

董事会布局:

board1|corners|centers
0 1 2 | 0   2 |   1  
3 4 5 |       | 3   5
6 7 8 | 6   8 |   7

board2|corners|centers
6 3 0 | 6   0 |   3
7 4 1 |       | 7   1
8 5 2 | 8   2 |   5

我提出的最快的方法是创建一个公共变量来分配数组条目,然后将内存复制回来。

int layout[9];
int pub_layout[9];

#include <cstring> // for std::memcpy
void rotate(int layout[])
{
    pub_layout[4] = layout[4]; // center

    pub_layout[0] = layout[6]; // corner four
    pub_layout[6] = layout[8];
    pub_layout[8] = layout[2];
    pub_layout[2] = layout[0];

    pub_layout[1] = layout[3]; // center four
    pub_layout[3] = layout[7];
    pub_layout[7] = layout[5];
    pub_layout[5] = layout[1];

    std::memcpy(layout,pub_layout,sizeof(pub_layout));
}

我见过类似的问题here,建议使用 int[] b = new int[] {b[6], b[3], b[0], b[7], b[4], b[1], b[8], b[5], b[2]};
虽然它的时钟速度要慢得多(不到单线程速度的一半)

两者都相对较快(see a test here

如果这不是最快的方法,那么是什么? 我怀疑C和C ++中的算法都是一样的。

3 个答案:

答案 0 :(得分:4)

通过这个,您可以获得memcpy呼叫和[4]至[4]分配。您丢失了putAside变量的两个分配。所以肯定会快一点。

int layout[9];
int putAside;

void rotate(int[] layout)
{
    putAside = layout[0];
    layout[0] = layout[6]; // corner four
    layout[6] = layout[8];
    layout[8] = layout[2];
    layout[2] = putAside;

    putAside = layout[1];
    layout[1] = layout[3]; // center four
    layout[3] = layout[7];
    layout[7] = layout[5];
    layout[5] = putAside;
}

答案 1 :(得分:1)

最快的方法可能是在非常紧密的循环中使用处理器缓存:

void rotate(int in[3][3], int out[3][3])
{
    int i, j, k;
    for (i=0,k=2;i<3;i++,k--)
        for (j=0;j<3;j++)
            out[j][k] = in[i][j];
}

注意:board[9]相当于board[3][3],并将9个整数视为内存中连续3个3个整数的序列,因此如果您愿意:

void rotate(int in[9], int out[9])
{
    int i, j, k;
    for (i=0,k=2;i<3;i++,k--)
        for (j=0;j<3;j++)
            out[j*3+k] = in[i*3+j];
}

如果要求inout可以相同,那么您应该使用以下内容:

void rotate(int in[9], int out[9])
{
    int tmp[9];
    int i, j, k;
    for (i=0,k=2;i<3;i++,k--)
        for (j=0;j<3;j++)
            tmp[j*3+k] = in[i*3+j];
    //memcpy(out,tmp, sizeof(tmp));  // use this...
    for(i=0;i<9;i++) out[i]=tmp[i];  //..or this, whichever clocks faster
}

答案 2 :(得分:1)

如果您想要一种更灵活的方式来应用任何转换,那么以下内容也会非常快:

template <int _1, int _2, int _3, int _4, int _5, int _6, int _7, int _8, int _9>
struct transfomer {
    board& _in;
    operator board() const {
      return { _in[_1], _in[_2], _in[_3], _in[_4], _in[_5], _in[_6], _in[_7], _in[_8], _in[_9] };
    }
};

void rotate3(board& layout) {
  layout = transfomer<6, 3, 0, 7, 4, 1, 8, 5, 2>{layout};
}

这里我将board定义为:

typedef array<int, 9> board;

是的,它依赖于隐式转换运算符(通常是邪恶的IMO,但在这里很有用。)(注意:我对您的测试进行了一些调整以使用array<>并运行相同的测试表明上述代码与@Joel中的手动解决方案相比平均值略有差异