二分查找 - worst/avg 个案例

Binary search - worst/avg case

我发现很难理解 why/how 使用二进制搜索在 array/list 中搜索键的最坏和平均情况是 O(log(n))。

log(1,000,000) 只有 6。log(1,000,000,000) 只有 9 - 我明白了,但我不明白其中的解释。如果没有测试,我们怎么知道 avg/worst 的情况实际上是 log(n)?

我希望你们明白我想说的。如果没有,请告诉我,我会尝试以不同的方式解释。

最坏情况

每次二进制搜索代码做出决定时,它都会从考虑中消除一半的剩余元素。因此,您将每个决定的元素数量除以 2。

在您只剩下一个元素之前,您可以除以 2 多少次?如果n是元素的起始个数,x是你除以2的次数,我们可以这样写:

n / (2 * 2 * 2 * ... * 2) = 1 ['2' 重复 x 次]

或者,等价地,

n / 2^x = 1

或者,等价地,

n = 2^x

所以 n 的以 2 为底的对数给你 x,这是正在做出的决定的数量。

最后,你可能会问,如果我使用log base 2,为什么像你那样写成log base 10 也可以?基数无关紧要,因为差异是 only a constant factor,按大 O 表示法是 "ignored"。

平均情况

我看到你也问了平均情况。考虑:

  1. 数组中只有一个元素可以在第一次尝试时找到。
  2. 第二次尝试只能找到两个元素。 (因为第一次尝试后,我们选择了右半边或左半边。)
  3. 第三次尝试只能找到四个元素。

您可以看到模式:1, 2, 4, 8, ... , n/2。表示相同的模式向另一个方向发展:

  1. 一半的元素采取最大数量的决定来找到。
  2. 四分之一的元素少了一次查找决定。
  3. 等等

由于一半的元素花费的时间最长,因此其他元素花费的时间少多少并不重要。我们可以假设所有元素都花费了最多的时间,即使其中一半实际上花费了 0 时间,无论真实平均值是多少,我们的假设都不会超过两倍。我们可以忽略 "double" 因为它是一个常数因子。因此,就大 O 符号而言,平均情况与最坏情况相同。

对于二分查找,数组应该按升序或降序排列。

  1. 在每一步中,算法都会将搜索键值与数组中间元素的键值进行比较。
  2. 如果键匹配,则找到匹配元素并返回其索引或位置。
  3. 否则,如果搜索关键字小于中间元素的关键字,则算法对中间元素左侧的子数组重复其操作。
  4. 或者,如果搜索关键字更大,则算法对右侧的子数组重复其操作。
  5. 如果要查找的剩余数组为空,则在数组中找不到key,返回一个特殊的"not found"指示。

所以,二分查找是 dichotomic divide and conquer search algorithm。因此,执行搜索操作需要对数时间,因为在每次迭代中元素都减少了一半。

对于我们可以进行二进制搜索的排序列表,二进制搜索生成的每个 "decision" 都会将您的键与中间元素进行比较,如果大于则取列表的右半部分,如果小于则取右半部分取列表的左半部分(如果匹配,它将 return 该位置的元素)对于每个产生 O(logn) 的决定,您有效地将列表减半。

然而,二进制搜索仅适用于排序列表。对于未排序的列表,您可以从第一个元素开始直接搜索,产生 O(n) 的复杂度。

O(logn) < O(n)

虽然这完全取决于您要进行的搜索次数、您的输入等,但您的最佳方法是什么。

对于二进制搜索,先决条件是将排序数组作为输入。

• 列表排序后:
• 当然,我们不必查字典中的每个单词来查找单词。
• 一个基本策略是反复将搜索范围减半,直到找到值。
• 例如,在 9 #s below.v = 1 1 3 5 8 10 18 33 42
的列表中查找 5 • 我们首先从中间开始:8
• 由于 5<8,我们知道我们可以只看前半部分:1 1 3 5
• 再看中间的 #,缩小到 3 5
• 然后当我们减少到一个时我们停止 #: 5
需要多少比较:4 =log(base 2)(9-1)=O(log(base2)n)

int binary_search (vector<int> v, int val) {
 int from = 0;
 int to = v.size()-1;
 int mid;
 while (from <= to) {
  mid = (from+to)/2;
  if (val == v[mid])
    return mid;
  else if (val > v[mid])
    from = mid+1;
  else
    to = mid-1;
  }
 return -1;
}