如何计算二分查找复杂度

Posted

技术标签:

【中文标题】如何计算二分查找复杂度【英文标题】:how to calculate binary search complexity 【发布时间】:2012-01-01 08:58:31 【问题描述】:

我听说有人说,由于二进制搜索将搜索所需的输入减半,因此它是 log(n) 算法。由于我不是数学背景,我无法与之相关。有人可以更详细地解释一下吗?是不是跟对数级数有关系?

【问题讨论】:

这可能对你有帮助:***.com/a/13093274/550393 【参考方案1】:

⌊log₂(n) + 1⌋ 是在二分搜索中找到某物所需的最大比较次数。平均情况大约进行 log2(n) - 1 比较。这里有更多信息:

http://en.wikipedia.org/wiki/Binary_search#Performance

【讨论】:

【参考方案2】:

它没有一半的搜索时间,这不会使它成为 log(n)。它以对数方式减小它。对此稍加思考。如果您在一个表中有 128 个条目并且必须线性搜索您的值,那么平均可能需要大约 64 个条目才能找到您的值。那是 n/2 或线性时间。使用二分搜索,您可以在每次迭代中消除 1/2 的可能条目,这样最多只需进行 7 次比较即可找到您的值(128 的以 2 为底的对数为 7 或 2 的 7 次方为 128。)这是二分查找的威力。

【讨论】:

对于 necropost 很抱歉,但 128 并不是一棵均匀填充的树。我使用了一个基本示例来解决这个问题,我发现 7 个条目均匀地填充了具有 3 层的树。我计算出复杂度应该是 17/7(比较总和的平均值),即 2.43。但是 log2(7) 是 2.81。那么我在这里错过了什么? 两个答案 - 这里的第一个:即使数学没有错误,我们可以看到 2.43 的平均值仍然优于线性的 3.5 平均值,这是一个较低的值。一旦进入 100 个条目,log2() 就比线性要好得多。我想你已经看到了,所以继续下一步。 第二个答案:我不确定你有什么样的树,其中 7 已经填写了所有内容。当我想到一棵有 8 个条目的完美树时,我看到一棵 3 层深的树,总共有 8 个叶子。在这棵树中,无论您搜索哪个数字,从根到叶总共需要 3 次比较。对于 7 个条目,其中一个路径将少进行一次比较,因此 20/7(3 个比较的 6 个节点,2 个比较的 1 个节点)约为 2.85。 Log2(7) 约为 2.81。我没有数学背景来解释 .04 的差异,但我想这与没有可用的小数位或其他魔法有关 :) 数字是叶子的数量!?不是节点数?好吧,那是我遗漏的一大块信息。对我来说,这个函数基于叶子似乎很奇怪,因为每个分支节点也是一个潜在的停止点。无论如何,感谢您为我解决这个问题!【参考方案3】:

二分搜索的工作原理是将问题反复分成两半,如下所示(细节省略):

在 [4,1,3,8,5] 中查找 3 的示例

    订购您的物品清单 [1,3,4,5,8] 看中间项(4), 如果它是您正在寻找的东西,请停止 如果更大,看前半部分 少的话看下半场 用新列表 [1, 3] 重复第 2 步,找到 3 并停止

当您将问题划分为 2 时,这是一个 bi-nary 搜索。

搜索只需要 log2(n) 个步骤即可找到正确的值。

如果您想了解算法复杂性,我会推荐 Introduction to Algorithms。

【讨论】:

【参考方案4】:

二分查找算法的时间复杂度属于O(log n)类。这称为big O notation。您应该解释这一点的方式是,在给定大小为 n 的输入集的情况下,函数执行时间的渐近增长不会超过 log n

这只是正式的数学术语,以便能够证明陈述等。它有一个非常简单的解释。当 n 变得非常大时,log n 函数将超过执行该函数所需的时间。 “输入集”的大小 n 就是列表的长度。

简单地说,二分搜索在 O(log n) 中的原因是它在每次迭代中将输入集减半。在相反的情况下更容易考虑它。在 x 次迭代中,二分搜索算法最多可以检查多长的列表?答案是 2^x。从这里我们可以看到相反的是,对于长度为 n 的列表,二分搜索算法平均需要 log2 n 次迭代。

如果为什么它是 O(log n) 而不是 O(log2 n),那是因为简单地再放一遍 - 使用大 O 符号常量不算数。

【讨论】:

【参考方案5】:

这里有一种更数学的方式来看待它,虽然不是很复杂。 IMO 比非正式的更清晰:

问题是,你可以将 N 除以 2 多少次才能得到 1?这本质上是说,进行二分搜索(一半的元素),直到找到它。在公式中是这样的:

1 = N / 2x

乘以 2x

2x = N

现在做日志2

log2(2x)    = log2 N x * log2(2) = log2 N x * 1         = log2 N

这意味着您可以将 log N 次划分,直到所有内容都划分完毕。这意味着您必须除以 log N(“执行二进制搜索步骤”),直到找到您的元素。

【讨论】:

我刚刚计算到 t(n) = (2^2)*K。如何使其登录表单? 以图形方式解释相同的概念:***.com/a/13093274/550393 我缺少的部分是,如果您有一个包含 7 个条目的 BST,它的公式是什么?日志2(7)?我对所有可能的结果进行了蛮力计算,得出的答案不等于 log2(7),那我做错了什么? 比二叉树解释简单多了。 很好的答案【参考方案6】:

对于二分搜索, T(N) = T(N/2) + O(1) // 递归关系

应用大师定理计算递归关系的运行时间复杂度: T(N) = aT(N/b) + f(N)

这里,a = 1,b = 2 => log (a base b) = 1

同样,这里 f(N) = n^c log^k(n) //k = 0 & c = log (a base b)

所以,T(N) = O(N^c log^(k+1)N) = O(log(N))

来源:http://en.wikipedia.org/wiki/Master_theorem

【讨论】:

为什么当 a=1 和 b=2 时 log(a base b) 为 1,不应该为 0 吗? 它应该是零。这里的 c 也是零,因为它的 1=n^0。所以它的 O(n^0 log n)= O(log(n))【参考方案7】:

这里是wikipedia 条目

如果您看一下简单的迭代方法。您只是消除了一半要搜索的元素,直到找到所需的元素。

这是我们如何得出公式的说明。

假设最初你有 N 个元素,然后你要做的是 ⌊N/2⌋ 作为第一次尝试。其中 N 是下限和上限的总和。 N 的第一个时间值将等于 (L + H),其中 L 是第一个索引 (0),H 是您要搜索的列表的最后一个索引。如果你很幸运,你试图找到的元素将在中间[例如。您在列表 16, 17, 18, 19, 20 中搜索 18 然后计算 ⌊(0+4)/2⌋ = 2 其中 0 是下限(L - 数组第一个元素的索引)并且 4 是上限(H - 数组最后一个元素的索引)。在上述情况下,L = 0 和 H = 4。现在 2 是您正在搜索找到的元素 18 的索引。答对了!你找到了。

如果案例是不同的数组15,16,17,18,19,但您仍在搜索 18,那么您将不走运,您将首先执行 N/2(即 ⌊(0+ 4)/2⌋ = 2 然后意识到索引 2 处的元素 17 不是您要查找的数字。现在您知道在下一次尝试迭代搜索时不必查找数组的至少一半方式。您的搜索工作量减半。因此,基本上,每次您尝试查找在之前的尝试中找不到的元素时,您不会搜索之前搜索的元素列表的一半。

所以最坏的情况是

[N]/2 + [(N/2)]/2 + [((N/2)/2)]/2..... 即: N/21 + N/22 + N/23 +..... + N/2x .....

直到……您完成搜索,您要查找的元素在列表末尾的位置。

这表明最坏的情况是当您达到 N/2x 时,x 等于 2x = N

在其他情况下 N/2x 其中 x 满足 2x

现在因为数学上最坏的情况是 2x = N => log2(2x) = log2(N) => x * log2(2) = log2(N) => x * 1 = log2(N) => 更正式的⌊log2(N)+1⌋

【讨论】:

究竟如何获得更正式的版本? 使用了楼层函数。详细信息在答案中提供的 wiki 链接 (en.wikipedia.org/wiki/Binary_search_algorithm) 的性能部分中。【参考方案8】:

T(n)=T(n/2)+1

T(n/2)=T(n/4)+1+1

把The(n/2)的值放在上面,所以T(n)=T(n/4)+1+1 . . . . T(n/2^k)+1+1+1.....+1

=T(2^k/2^k)+1+1....+1 到 k

=T(1)+k

我们取了 2^k=n

K = log n

所以时间复杂度是 O(log n)

【讨论】:

【参考方案9】:

由于我们每次将列表减半,因此我们只需要知道在继续将列表除以 2 时得到 1 的步数。在下面给定的计算中,x 表示我们划分一个列表直到我们得到一个元素的时间(在最坏情况下)。

1 = N/2x

2x = N

取log2

log2(2x) = log2(N)

x*log2(2) = log2(N)

x = log2(N)

【讨论】:

【参考方案10】:
ok see this
for(i=0;i<n;n=n/2)

i++;

1. Suppose at i=k the loop terminate. i.e. the loop execute k times.

2. at each iteration n is divided by half.

2.a n=n/2                   .... AT I=1
2.b n=(n/2)/2=n/(2^2)
2.c n=((n/2)/2)/2=n/(2^3)....... aT I=3
2.d n=(((n/2)/2)/2)/2=n/(2^4)

So at i=k , n=1 which is obtain by dividing n  2^k times
n=2^k
1=n/2^k 
k=log(N)  //base 2

【讨论】:

【参考方案11】:

T(N) = T(N/2) + 1

T(N) = T(N/2) + 1 = (T(N/4) + 1)+ 1

...

T(N) = T(N/N) + (1 + 1 + 1 +... + 1) = 1 + logN (base 2 log) = 1 + logN

所以二分查找的时间复杂度是O(logN)

【讨论】:

【参考方案12】:

让我举个例子让大家容易理解。

为简单起见,我们假设数组中有 32 个元素,按排序顺序排列,我们使用二分法搜索其中的一个元素。

1 2 3 4 5 6 ... 32

假设我们正在搜索 32。 在第一次迭代之后,我们将剩下

17 18 19 20 .... 32

第二次迭代后,我们将剩下

25 26 27 28 .... 32

第三次迭代后,我们将剩下

29 30 31 32

第四次迭代后,我们将剩下

31 32

在第五次迭代中,我们将找到值 32。

所以,如果我们把它转换成一个数学方程,我们会得到

(32 X (1/25)) = 1

=> n X (2-k) = 1

=> (2k) = n

=> k log22 = log2n

=> k = log2n

因此证明。

【讨论】:

【参考方案13】:

假设二分搜索中的迭代在 k 次迭代后终止。 在每次迭代中,数组被除以一半。因此,假设任何迭代的数组长度为 n 在第 1 次迭代中,

Length of array = n

在第 2 次迭代中,

Length of array = n⁄2

在第 3 次迭代中,

Length of array = (n⁄2)⁄2 = n⁄22

因此,在迭代k之后,

Length of array = n⁄2k

另外,我们知道之后 k次分割后,数组的长度变为1 因此

Length of array = n⁄2k = 1
=> n = 2k

在两边应用日志功能:

=> log2 (n) = log2 (2k)
=> log2 (n) = k log2 (2)
As (loga (a) = 1)

因此,

As (loga (a) = 1)
k = log2 (n)

因此二分查找的时间复杂度为

log2 (n)

【讨论】:

应该可以将您的答案发送到最顶层。【参考方案14】:

这是使用主定理的解决方案,带有可读的 LaTeX。

对于二分搜索递归关系中的每个递归,我们将问题转换为一个子问题,运行时间为 T(N/2)。因此:

代入主定理,我们得到:

现在,因为 是 0 而 f(n) 是 1,我们可以使用主定理的第二种情况,因为:

这意味着:

【讨论】:

以上是关于如何计算二分查找复杂度的主要内容,如果未能解决你的问题,请参考以下文章

二分查找思想

java 二分查找计算时间复杂度

你真的会二分查找吗?—面试中的二分查找

Day 18:二分查找算法

二分查找模板

算法学习|二分查找