我对来自Collections
的binarySearch
的效果分析感到困惑
它说:
如果指定的列表未实现RandomAccess接口 并且很大,这个方法会做一个基于迭代器的二进制搜索 执行O(n)链接遍历和O(log n)元素比较。
我不确定如何解释此O(n)
+ O(log n)
。
我的意思是,这不仅仅是简单地遍历链表并进行比较吗?我们仍然只获得O(n)
。
那么这句话对绩效意味着什么呢?如上所述,我无法理解与链表中的简单线性搜索的区别。
我在这里误解了什么?
答案 0 :(得分:11)
首先,您必须明白,如果没有RandomAccess
接口,binarySearch
不能简单地从列表中访问随机元素,而是必须使用迭代器。这会导致O(n)
费用。当集合实现RandomAccess
时,每个元素访问的成本为O(1)
,并且就渐近复杂性而言可以忽略。
由于O(n)
大于O(log n)
,因此它始终优先于O(log n)
并支配复杂性。在这种情况下,binarySearch
具有与简单线性搜索相同的复杂性。 那么优势是什么?
线性搜索执行O(n)
比较,而O(log n)
执行binarySearch
而不进行随机访问。当O(logn)
之前的常数很高时,这一点尤为重要。用简单的英语:当单个比较与推进迭代器相比具有非常高的成本时。这可能是非常常见的情况,因此限制比较的数量是有益的。利润!
答案 1 :(得分:2)
二进制搜索不适用于链接列表。该算法应该受益于带有随机访问的排序集合(如普通数组),它可以从一个元素快速跳转到另一个元素,在每次迭代时将剩余的搜索空间分成两部分(因此O(log N)
时间复杂度。
对于链表,有一个修改后的版本,它遍历所有元素(在最坏的情况下需要通过2n
元素),但不是比较每个元素,而是“探测”列表仅指定位置(因此与线性搜索相比,比较的数量较少)。
由于与普通指针迭代相比,比较通常稍微昂贵,因此总时间应该更低。这就是log N
部分被单独强调的原因。