为什么二元搜索比三元搜索快?


49

在搜索的阵列使用二进制搜索元素需要,在最坏情况下日志2次 Ñ迭代因为,在每一个步骤中,我们修剪我们的搜索空间的一半。相反,如果我们使用“三元搜索”,则每次迭代都将减少三分之二的搜索空间,因此最坏的情况应该是log 3 N < log 2 N迭代...ñ日志2⁡ñ日志3⁡ñ<日志2⁡ñ

似乎三元搜索更快,那么为什么要使用二元搜索呢?


3
关于第四元搜索,难道不能使用相同的推理吗?甚至小数搜索...或任何大于2
— 德alar'cop

4
请阅读有关B +树的信息
— arunmoezhi14年

5
对于现代硬件上的中小型问题,线性搜索通常比二进制搜索要快,这是因为它具有缓存一致性,并且几乎所有分支都可以正确预测。
— 别名2014年

2
如果2 * log_3(N)= log_3(N ^ 2)符合您的直觉,则也是如此。
— PawelP 2014年

6
让我们用直觉的术语来表达。如果使用基于3的搜索会更快,因为每次迭代都会减少搜索空间,那么使用基于百万的搜索不是更快吗?但是您可以很容易地看到,平均而言,您必须在每次迭代中进行500,000次检查才能确定包含目标的百万分之一。显然,将搜索空间减少到每次迭代的一半,而不会再减少,一步就可以可靠地为您提供最多的信息。
— ErikE 2014年

Answers:


76

如果应用二进制搜索,您可以许多比较。如果应用三元搜索,你有2 ⋅ 日志3(ñ )+ Ö (1 )多比较,在每个步骤中,您需要执行2个比较削减搜索空间分为三个部分。现在,如果你做数学题,你可以观察到: 2 ⋅ 日志3(ñ )+ Ö (1 )= 2 ⋅ 日志(2

日志2⁡(ñ)+Ø(1个)
2⋅日志3⁡(ñ)+Ø(1个)
由于我们知道2⋅日志(2)
2⋅日志3⁡(ñ)+Ø(1个)=2⋅日志⁡(2)日志⁡(3)日志2⁡(ñ)+Ø(1个)
,实际上我们可以通过三元搜索获得更多比较。2⋅日志⁡(2)日志⁡(3)>1个

顺便说一句:如果比较比较昂贵并且可以并行化,那么搜索可能很有意义,因为这样可以应用并行计算机。ñ

注意,可以很容易地将参数推广到搜索。你只需要表明函数˚F (ķ )= (ķ - 1 )⋅ 日志(2 )ñ是严格的单调递增的k的整数值。F(ķ)=(ķ-1个)⋅日志⁡(2)日志⁡(ķ)ķ


1
而且LHS是线性的,RHS是对数的,因此它对四进制或其他均无济于事....不错的解释....谢谢
— 均方

3
仅出于完整性考虑:请注意,诸如元素比较数之类的抽象度量可能会或可能不会主导实际运行时。特别是,您可能必须考虑使用任一搜索在长数组上可能会遇到多少高速缓存未命中。(在这里,它们是巧合的。我只是在注意这一点,因为OP会问:“为什么会更快?”,并且用抽象的方法回答某些算法可能会产生误导。)
— Raphael

10
在三元搜索中,有1/3的时间只需要进行1次比较(进行较低的比较:如果在较低的三分之一中,则不需要进行第二次比较)。这使得三元数仅慢5%,而不是25%(在这个我们只关心比较计数的世界中)。我不确定如何将其推广到n元,尽管我怀疑它永远不会比二进制快。
— 亚伦·迪富

2
@AaronDufour:由于可以先比较中间项然后忽略其他比较的结果来进行四元搜索,所以四元搜索更快的唯一方法是并行进行三个比较比两个比较便宜可以顺序执行。
— 超级猫2014年

1
@AaronDufour但是您正在分摊要搜索的元素,但我不清楚为什么这样可以。在最坏的情况下,两个比较都可能在每个步骤中执行。
— Sasho Nikolov 2014年

26

DCTLib是正确的,但请稍等一会。

按照您的逻辑,n -ary应该是最快的。但是,如果考虑一下,n -ary完全等于常规迭代搜索(只是对列表进行1到1迭代,但顺序相反)。首先,您选择列表中的最后一项(或最后一项),然后将该值与比较值进行比较。然后,从列表中删除该项目,然后选择新列表中的最后一个项目,它只是数组中倒数第二个值。每次,您一次只能消除1个值,直到找到您的值为止。

相反,您应该这样考虑-每次迭代如何从列表中消除最多的值?在二分查找中,您总是消除列表的一半。在三元搜索中,您有可能(实际上有33.33%的机会)消除列表的2/3,但有更大的机会(66.66%)则只会消除列表的1/3。为了计算O(n),您需要查看最坏的情况,即1/3,小于1/2。随着您越来越接近n,情况变得更糟。

二进制搜索不仅可以改善最坏的情况,而且平均时间也会得到改善。查看期望值(我们平均可以删除列表的哪一部分),我们使用以下公式:

(P_lower)x(如果较低的话可以去除的部分)+(P_higher)x(如果较高的话可以去除的部分)= E

对于二进制搜索,这是.5x.5 + .5x.5 = .5(我们总是删除列表的一半)。对于三元搜索,此值是.666x.333 + .333x.666 = 0.44,或者在每个步骤中,我们很可能只会删除列表的44%,因此平均而言,效率不如二元搜索。该值的峰值为1/2(列表的一半),并随着您接近n(反向迭代)和0(常规迭代)而减小。

好的,所以我撒谎了..涉及到一点数学,但我希望对您有所帮助!


1
这是一个很好的答案。
— The_Sympathizer 2015年

Ya边界分析可帮助您理解困难的数学知识!n元顺序搜索具有与线性搜索O(n)相同的成本。
— 舒瓦

-2

请注意log(N)vs 2 log(N)比较参数是基于对算法的幼稚解释。如果我实际坐下来并用x86汇编语言编写,结果将是相反的。问题在于,对于测试用例使用整数,再加上不能删除冗余比较的不够智能的编译器。使用字符串和适当的字符串比较函数重试,并对其进行编码以在每个循环中调用一次比较函数,您会发现三元搜索再次变得更快。


2
当然,如果每次迭代只进行一次比较,三元搜索就会更快。但是,无论是字符串还是整数,都不能。
— FrankW 2014年

比较不会是多余的,并且问题与编译器无关。为了将搜索空间分为三部分,您需要进行两次比较。在二元搜索中,您只需要与中间元素进行比较,然后就可以知道结果将位于搜索空间的哪一半。对于三元搜索,您需要与元素之间进行比较的1/3列表以及列表中的2/3。您要比较的数据类型或所用的语言无关紧要。当然,如果项目在第1个第3个,则可以在进行1次比较后停止。
— reirab 2014年

2
在某些平台上,三元搜索可能会更快,因为允许CPU有更多时间在需要比较之前从RAM中提取操作数。但这完全取决于所使用的平台及其延迟和缓存。
— jpa 2014年

1
糟透了-三元搜索的定义错误。
— 约书亚
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.