快速平均而不分裂

时间:2009-06-19 21:51:32

标签: algorithm language-agnostic bit-manipulation binary-search

我有一个二进制搜索循环,在执行路径中被多次命中。

分析器显示搜索的分割部分(找到给定搜索范围的高和低索引的中间索引)实际上是搜索中成本最高的部分,大约为4倍。

(我认为)有效的二进制搜索找到确切的中间值并不重要,只是中间附近的值,在任何一个方向都没有偏差。

是否有一种比较麻烦的算法用更快的速度替换mid = (low + high) / 2

编辑:语言是C#,但是等效的位操作在任何语言中都有效(尽管它可能没有性能优势),这就是我离开C#标签的原因。

6 个答案:

答案 0 :(得分:19)

这是一个没有溢出问题的平均值的黑客版本:

unsigned int average (unsigned int x, unsigned int y)
{
  return (x&y)+((x^y)>>1);
}

答案 1 :(得分:12)

int mid = (low + high) >>> 1;

建议在整数溢出成为问题时使用“(低+高)/ 2”进行中点计算won't work correctly

答案 2 :(得分:7)

您可以使用位移并克服可能的溢出问题:

low + ((high-low) >> 1)

但是我必须承认,我希望现代编译器和解释器能够将2除(或除以2的任何其他常数幂)除以位移,所以不确定它是否真的有用 - 试试看。

答案 3 :(得分:5)

为了进一步扩展Nils的回答 Richard Schroeppel 发明了这一点。

http://www.inwap.com/pdp10/hbaker/hakmem/boolean.html#item23

  

第23项(Schroeppel):

     

(A AND B)+(A OR B)= A + B =(A XOR B)+ 2(A和B)。

(A + B)/2 = ((A XOR B) + 2(A AND B))/2
          =  (A XOR B)/2  + (A AND B)
          =  (A XOR B)>>1 + (A AND B)


avg(x,y){return((x^y)>>1)+(x&y);}

(A AND B) + (A OR B) = A + B因为A AND B给出了共享(A和B之间)2的幂的总和,A OR B给出了共享和非共享的那些,因此:

(A AND B) + (A OR B) = 
   (sum of shared powers of two) + 
   ((sum of shared powers of two) + (sum of unshared powers of two)) = 
     (sum of shared powers of two) + 
     ((sum of shared powers of two) + (sum of powers of two of A only) + 
     (sum of powers of two of B only)) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B. 

A XOR B给出了A和B之间不同位的映射。因此,

A XOR B = (sum of powers of two of A only) + (sum of powers of two of B only). 

因此:

2(A AND B) + (A XOR B) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B.

答案 4 :(得分:0)

如果我没记错的话,有些情况下使用数组的确切中间实际上可能会更慢。解决方案是随机选择将数组平分的索引。同样适用于确定阵列中值的算法。

我不记得确切的细节,但我记得在iTunes的MIT algorithms series的第6讲中听到了。

答案 5 :(得分:0)

尝试低+((高 - 低)/ 2))。这应该有效,因为你只取两个数字的平均值。如果二进制搜索列表相当大,这将减少算法所花费的时间,因为高 - 低远低于高+低。