优化此基于查询的搜索

时间:2012-05-14 18:33:39

标签: algorithm bit-manipulation

我们有两个N位数(0

  • set_a idx x:将A [idx]设置为x,其中0 <= idx&lt; N,其中A [idx]是A的最低有效位。

  • set_b idx x:将B [idx]设置为x,其中0 <= idx&lt; Ñ

  • get_c idx:打印C [idx],其中C = A + B,0 <= idx

现在,我已经尽可能地优化了代码。

  • 首先,我尝试使用int数组来表示a,b和c。对于每次更新,我计算c并在查询时返回第i位。这很慢。仅清除4/11测试用例。

  • 我转而使用布尔数组。它比int数组方法快2倍左右。清除7/11测试用例。

  • 接下来,我发现我不需要计算c来计算A + B的idx位。我将从idx向右扫描A和B,直到找到[i] = b [i] = 0或a [i] = b [i] = 1。如果a [i] = b [i] = 0,那么我只是向左加到idx th bit,从初始进位= 0开始。如果a [i] = b [i] = 1,那么我只是从左边加到idx,从初始进位= 1开始。 这更快,但只清除了8/11个测试用例。

  • 然后,我想出一次,我到了位置i,a [i] = b [i] = 0或a [i] = b [i] = 1,然后我不需要加起来朝着idx的位置。如果a [i] = b [i] = 0,那么答案是(a [idx] + b [idx])%2,如果a [i] = b [i] = 1,那么答案是(a [ IDX] + b [IDX] 1)%2。它的速度提高了大约40%,但仍然只清除了8/11个测试用例。

现在我的问题是如何降低这3个''硬'的测试用例?我不知道它们是什么,但程序花了> 3秒来解决问题。

以下是代码:http://ideone.com/LopZf

2 个答案:

答案 0 :(得分:0)

一种可能的优化是替换

(a[pos]+b[pos]+carry)%2

a[pos]^b[pos]^carry

XOR运算符(^)执行加法模2,使得可能不需要昂贵的mod运算(%)。根据语言和编译器的不同,编译器可能会在执行功率为2的mod时为您进行优化。但是,由于您是微优化,因此只需进行一项简单的更改即可消除对优化后的优化。场景。

http://en.wikipedia.org/wiki/Exclusive_or

这只是一个简单易懂的建议。正如其他人所建议的那样,使用压缩的int来表示你的位数组也可能会改善你的代码最糟糕的情况。这将是最高有效位的get_c函数,其中A或B(但不是两者)对于所有其他位置为1,需要将每个位位置扫描到最低有效位以确定进位。如果您使用压缩的int作为比特,那么只需要大约1/32的操作(假设32位整数)。然而,使用压缩的int比使用简单的布尔数组(实际上可能只是一个字节数组)要复杂得多。

C/C++ Bit Array or Bit Vector

Convert bit array to uint or similar packed value

http://en.wikipedia.org/wiki/Bit_array

Stackoverflow和net上有很多其他的例子,就像使用int数组一样。

答案 1 :(得分:0)

这是一个看起来有点算法的解决方案。我用字节来演示它,但当然你可以使用32位字轻松优化算法(我想你的机器现在有64位算术)。

void setbit( unsigned char*x,unsigned int idx,unsigned int bit)
{
   unsigned int digitIndex = idx>>3;
   unsigned int bitIndex = idx & 7;
   if( ((x[digitIndex]>>bitIndex)&1) ^ bit) x[digitIndex]^=(1u<<bitIndex);
}
unsigned int getbit(unsigned char *a,unsigned char *b,unsigned int idx)
{
   unsigned int digitIndex = idx>>3;
   unsigned int bitIndex = idx & 7;
   unsigned int c = a[digitIndex]+b[digitIndex];
   unsigned int bit = (c>>bitIndex) & 1;
   /* a zero bit on the right will absorb a carry, let's check if any */
   if( (c^(c+1))>>bitIndex )
   {
      /* none, we must check if there's a carry propagating from the right digits */
      for(;digitIndex-- > 0;)
      {
         c=a[digitIndex]+b[digitIndex];
         if( c > 255 ) return bit^1; /* yes, a carry */
         if( c < 255 ) return bit;   /* no carry possible, a zero bit will absorb it */
      }
   }
   return bit;
}

如果你发现任何神秘的东西,请问。 编辑:oops,我将零位条件反转......