一个 O(log n)的例子

介绍

请考虑以下问题:

L 是一个包含 n 有符号整数的排序列表(n 足够大),例如 [-5, -2, -1, 0, 1, 2, 4](这里,n 的值为 7)。如果已知 L 包含整数 0,那么如何找到 0 的索引?

天真的方法

首先想到的是只读取每个索引,直到找到 0。在最坏的情况下,操作次数是 n,因此复杂度为 O(n)

这适用于 n 的小值,但是有更有效的方法吗?

二分法

考虑以下算法(Python3):

a = 0
b = n-1
while True:
  h = (a+b)//2 ## // is the integer division, so h is an integer
  if L[h] == 0:
    return h
  elif L[h] > 0:
    b = h
  elif L[h] < 0:
    a = h

ab 是要找到 0 的索引。每次我们进入循环时,我们使用 ab 之间的索引,并使用它来缩小要搜索的区域。

在最坏的情况下,我们必须等到 ab 相等。但这需要多少次操作?不是 n,因为每次我们进入循环时,我们将 ab 之间的距离除以 2。相反,复杂性是 O(log n)。

说明

注意:当我们写 log 时,我们指的是二进制对数,或者 log base 2(我们将写入“log_2”)。由于 O(log_2 n)= O(log n)(你可以进行数学运算),我们将使用 log 而不是“log_2”。

让我们调用 x 操作的数量:我们知道 1 = n /(2 ^ x)。

所以 2 ^ x = n,然后 x = log n

结论

当面对连续的划分(无论是两个还是任何数字)时,请记住复杂性是对数的。