为什么在二分查找中使用中间表达式的上限值是错误的?

时间:2014-10-27 16:37:57

标签: java binary-search

在典型的二进制搜索算法中(例如在Java中),我们发现使用分层而不是分区的上限来选择中间元素:

public static void binarySearch(int[] array, int lowerbound, int upperbound, int key)
{
  int comparisonCount = 0;    // counting the number of comparisons (optional)        
  while (lowerbound <= upperbound)
  {
    final int position = (lowerbound + upperbound) / 2;
    ++comparisonCount;
    if (array[position] == key)
    {
      System.out.println("The number was found in array subscript " + position + '.');
      System.out.println("The binary search found the number after " + comparisonCount +
                         " comparisons.");
      return;
    }
    if (array[position] > key)             // If the number is > key, ..
    {                                      // decrease position by one. 
      upperbound = position - 1;   
    }                                                             
    else                                                   
    {                                                        
      lowerbound = position + 1;           // Else, increase position by one. 
    }
  }
  System.out.println("Sorry, the number is not in this array. The binary search made "
                     + comparisonCount  + " comparisons.");
}

这里position的公式使用向下舍入的整数除法(例如3.5变为3)。我的教授说,将其四舍五入的替代方案 导致错误。如果是这样,它是什么?为什么有必要将值向下舍入而不是向上?

1 个答案:

答案 0 :(得分:1)

假设序列中只有一个要搜索的元素。您的下限为零,上限为1,因为边界表示半开范围。这具有从上限减去下限的属性,产生序列的长度。

如果下限为零且上限为1,则计算表达式

(ceiling (+ lower-bound upper-bound) 2)

你得到一个,这不是这个序列中唯一元素的有效索引。唯一有效的索引是零,这是更传统的表达式

(floor (+ lower-bound upper-bound) 2)

会屈服。

如果您有三个元素,其中中间元素的索引显然为1,请再次考虑

(ceiling (+ 0 3) 2)

等于2,这是 last 元素的索引,而不是中间元素。

我们可以通过询问中间元素的这种糟糕选择是否最终会产生正确答案来进一步探索您的问题。算法仍然会朝着正确的方向(或者这个元素所属的位置,如果序列中没有)的方向向右移动,但是当所考虑的子序列再次缩小到一个元素时,算法会失败,因为它会错误地选择一个大于剩余元素的索引。