快速有效的阵列查找和修改

时间:2014-11-21 03:03:29

标签: arrays lookup

我一直想知道以下两种方法中的哪一种更快或更好。

我当前的方法

我开发了一个国际象棋游戏,这些棋子被存储为数字(实际上是保存内存的字节)到一维数组中。光标的位置对应于数组中的索引。要在阵列中的当前位置访问该块很容易(piece = pieces[cursorPosition])。

问题是要获取x和y值以检查移动是否为有效移动需要除法和模运算符(x = cursorPosition % 8; y = cursorPosition / 8)。

同样,当使用x和y来检查移动是否有效时(由于填充整个页面的原因,你必须这样做),你必须做类似的事情 - 纯粹作为一个例子 - if pieces[y * 8 + x] != 0: movePiece = False 。显而易见的问题是必须多次y * 8 + x来访问数组。

最终,这意味着获得一个片段是微不足道的,但是获得x和y需要另外一点内存并且每一轮计算它的时间非常短。

更传统的方法

使用二维数组,人们可以更容易地实现上述过程,除了现在查找片段更加困难并且使用更多内存这一事实。 (即piece = pieces[cursorPosition[0]][cursorPosition[1]]piece = pieces[x][y])。

我认为这不是更快,而且它看起来并不会减少内存密集度。

目标

我的最终目标是拥有使用最少内存的最快代码。这将是为unix终端开发的(如果我可以弄清楚如何使用Ansi转义序列来表示没有颜色的部分,可能是Windows CMD)我将使用安全(加密协议和结构)TCP连接来连接人p2p下国际象棋或其他东西,我不知道人们会有多少记忆,计算机的速度有多快,或者他们的网络连接有多强。

我也想学习以最好的方式做到这一点,看看是否可以做到。

-

我想我的问题是以下之一:

假设涉及移动验证的计算稍多(这意味着必须经常使用y * 8 + x),上述哪种方法更好?

是否有一种方法既包含1d和2d数组的优点,又没有我描述的那么多缺点?

2 个答案:

答案 0 :(得分:2)

首先,您应该对代码进行分析,以确保这确实是一个值得花时间的瓶颈。

其次,如果你将你的位置表示为无符号字节,将其分解为X和Y坐标将非常快。如果我们使用以下C代码:

int getX(unsigned char pos) {
   return pos%8;
}

我们使用gcc 4.8 -O2获得以下程序集:

getX(unsigned char):
    shrb    $3, %dil
    movzbl  %dil, %eax
    ret

如果我们得到Y坐标:

int getY(unsigned char pos) {
   return pos/8;
}

我们使用gcc 4.8 -O2获得以下程序集:

getY(unsigned char):
    movl    %edi, %eax
    andl    $7, %eax
    ret

答案 1 :(得分:1)

这个问题没有简短的答案;这一切都取决于你花在优化上的时间。

在某些体系结构中,二维数组可能比一维更好。在其他体系结构中,位图整数可能是最好的。

不要担心分裂和乘法。 你正在划分,调制和乘以8。 这个数字是2的幂,因此任何计算机都可以使用按位运算来实现结果。

  • (x * 8)与(x <3)
  • 相同
  • (x%8)与(x&amp;(8-1))
  • 相同
  • (x / 8)与(x>&gt;&gt; 3)
  • 相同

这些操作通常在单个时钟周期内执行。在许多现代架构中,它们可以在不到一个时钟周期内执行(包括ARM架构)。 不要担心使用按位运算符而不是*,%和/。如果您使用的编译器不到十年,它将为您优化并使用按位操作。

您应该关注的是,例如,找出移动是否合法是多么容易。这将有助于您的计算机玩家“快速思考”。

如果您使用的是8 * 8阵列,那么通过检查是否只更改了x或y,您可以轻松查看城堡的移动位置。如果检查女王,则X必须相同或移动与Y位置相同的步数。

如果你使用一维数组,你也有优势。

但在性能方面,使用16x16阵列或1x256阵列可能是个不错的主意。 用0x80值填充整个数组(例如“非法位置”)。然后用0x00填写合法字段。

如果使用1x256阵列,则可以检查索引的第3位和第7位。如果设置了任何一个,那么该位置在董事会之外。 测试可以这样做:

if(position & 0x88)
{
    /* move is illegal */
}
else
{
    /* move is legal */
}

......或......

if(0 == (position & 0x88))
{
    /* move is legal */
}

'position'(索引)应该是无符号字节(C中的uint8_t)。这样,您就不必担心指向缓冲区外。

有些人通过使用64位位图整数来优化他们的国际象棋引擎。 虽然这有利于快速比较位置,但它还有其他缺点;例如,检查骑士的举动是否合法。 但是,要说哪个更好是不容易的。

就个人而言,我认为一维数组通常可能是最好的方法。 我建议熟悉(非常熟悉)AND,OR,XOR,位移和旋转。

有关详细信息,请参阅Bit Twiddling Hacks