是否可以在二次搜索算法的每次迭代中只进行一次比较?

时间:2010-08-17 07:20:26

标签: c algorithm optimization micro-optimization

在二进制搜索算法中,我们有两个比较:

if (key == a[mid]) then found;

else if (key < a[mid]) then binary_search(a[],left,mid-1);
      else binary_search(a[],mid+1,right);

我是否有办法只进行一次比较,而不是上述两种比较。

-

由于

Alok.Kr。

7 个答案:

答案 0 :(得分:14)

请参阅:

http://en.wikipedia.org/wiki/Binary_search_algorithm#Single_comparison_per_iteration

取自维基:

   low = 0
   high = N
   while (low < high) {
       mid = low + ((high - low) / 2)
       if (A[mid] < value)
           low = mid + 1;
       else
            //can't be high = mid-1: here A[mid] >= value,
            //so high can't be < mid if A[mid] == value
            high = mid;
   }
   // high == low, using high or low depends on taste
   if ((low < N) && (A[low] == value))
       return low // found
   else
       return -1 // not found

来自wiki的优点/缺点: “这种方法放弃了在发现匹配时提前终止的可能性,因此成功的搜索具有log2(N)次迭代而不是预期的log2(N)-1次迭代。另一方面,这种实现使得比较更少:log2(N )对于1.5的两次测试实现(log2(N) - 1),对于大于8的N,小于预期的比较次数。“

答案 1 :(得分:4)

是。只是不要从递归调用中消除mid

if ( left == right ) return NULL;
if ( left + 1 == right ) return key == a[left]? &a[left] : NULL;

mid = left + ( right - left / 2 );

if (key < a[mid]) return binary_search(a[],left,mid-1);
else return binary_search(a[],mid,right); // include `mid` in next round

您只需要在每次递归时消除一半的集合以实现O(logN)性能。通过消除半+ 1来超越你。

如果在递归期间仅使用<,算法将找到不小于key的最小元素(但可能大于key)。通过执行单个相等测试来完成。

答案 2 :(得分:1)

在汇编程序中,您可以:

cmp key,a[mid]
beq found
bge else

因此,如果你的编译器真的擅长窥视孔优化,它可能已经为你做了这个。

答案 3 :(得分:0)

这是递归算法。第一个比较是停止标准和第二个实际搜索,因此您无法删除它们。

首先,你问什么时候你已经找到了元素,然后在第二个元素的哪个部分寻找元素。因此,您不能仅根据一次比较做出这些决定。

答案 4 :(得分:0)

首先要做的事情是:你需要优化程序吗?你有没有测量过知道你需要做什么?它在这个功能中吗?

对于基本类型,第二次比较与获得的操作一样快。比较的较高成本是将元素加载到适当的寄存器中,这是第一次比较所需要的。执行该比较后,该值已经在寄存器中,第二个操作需要单个处理器指令加上分支错误预测的可能成本。

假设整数类型,如果编译器无法执行尾递归优化,则算法的处理器时间成本很可能由递归调用的成本决定。如果您确实需要对此进行优化,请尝试使用所有优化标志进行编译并分析汇编程序以确定是否正在应用尾递归优化。如果没有,请手动将算法从递归转换为迭代。

这将产生两个影响:隐藏代码(避免修改干净的解决方案,除非你真的需要)并避免函数调用。

如果你是在谈论C ++,而且类型很复杂且重载的比较运算符很昂贵,性能的最快提升就是实现一个compare方法,该方法将返回小于0的负数0表示相等,如果大于,则为正数。然后在比较之前预先计算结果,然后执行仅整数检查。这将通过昂贵的比较将算法的总成本移除到真实对象的单个处理中,并将您置于原始假设中。

答案 5 :(得分:0)

for (step = 0; step < n; step <<= 1);

for (i = 0; step; step >>= 1)
    if (i + step < n && v[i + step] <= x)
        i += step;

答案 6 :(得分:0)

好的,这是Adobe的一个面试问题,我只想弄清楚如何做到这一点。

现在我已经找到了解决方案,所以我发帖

void binary_search (int a[] , int low ,  int high , int key )
{
    int mid = (low+high)/2;

    if (key == a[mid]) {
        printf ("Number Found\n");
        return;
    }

    else {
        int sign = Calc_sign (key-a[mid]);
        low = low*sign + (1-sign)*mid;
        high = mid*sign + (1-sign)*right;
        binary_search (a,low,high,key);
    }
}

int Calc_sign(int a) 
{
     return ( (a & 80000000) >> 31);
}

因此在代码中只有一个比较用于检查keyvalue是否与中间元素相同。

-

由于

Alok Kr。