【问题标题】:Why do binarySearch on list in Java?为什么二进制搜索在 Java 中的列表上?
【发布时间】:2012-02-11 01:04:32
【问题描述】:

鉴于列表已排序,我不确定为什么 List 作为一般数据结构应该具有二进制搜索算法。接受索引的get 方法不是按顺序遍历列表,至少对于List 的子类型LinkedList 而言是这样吗?如果是这样,与LinkedList 的顺序比较相比,我看不到使用binarySearch 的任何优势。当然,除非我们将 List 限制为 ArrayList,否则我们可以更有信心地进行 binarySearch。

我的理解正确吗?谢谢。

【问题讨论】:

  • “鉴于列表已排序” - 这不是给定的。
  • 我只是假设这是真的。或者我们总是可以先排序。
  • 你说得对,在 LinkedList 上进行二分搜索是个坏主意。
  • 好吧,javadoc 在这里会很有帮助:如果指定的列表没有实现RandomAccess 接口并且很大,这个方法将执行基于迭代器的二分查找,执行 O(n ) 链接遍历和 O(log n) 元素比较。

标签: java algorithm list data-structures binary-search


【解决方案1】:

有很多方法可以实现List。标准 Java 库中有 ArrayListLinkedListCopyOnWriteArrayList 等,以及除此之外的许多其他实现(VLists、循环缓冲区、倾斜二项式列表、extendible arrays2-3 finger trees 等.)。提供二进制搜索背后的想法是,虽然并非所有 List 实现都支持随机访问,但支持随机访问的实现将受益于提供二进制搜索的通用实现,这样每个数据结构的作者就不必从头开始重新实现它。例如,如果我实现了一个支持随机访问的疯狂的新列表结构,如果我实现 List 接口,我可以自动从 Collections 类中获取二进制搜索。

有趣的是,binarySearch 方法是这样编写的,它在实际执行二分搜索之前查看List 的类型并查看它是否实现了RandomAccess 接口。如果列表没有实现RandomAccess,则该方法不使用标准的二进制搜索,而是使用带有迭代器的修改后的二进制搜索,保证最多进行 O(n) 次迭代和 O(log n) 次比较。这个想法是跟踪最后一个探测器降落的位置,然后向前或向后走适当的步数以找到下一个探测器位置,等等。完成的总工作最多为 n/2 + n/4 + n /8 + n/16 + ... = 2n,所以在最坏的情况下,它只是最坏情况下的线性搜索的两倍。

简而言之,提供binarySearch 的通用实现并不总是可以快速搜索列表以查找某些内容,但对于支持快速访问的结构,它可以产生巨大的差异并节省大量实现者时间。此外,对在 O(n) 时间内运行的修改后的二进制搜索进行优雅降级意味着该实现不会比标准线性扫描差太多。

这种推理类似于 C++ 算法设计背后的推理,后者对通用值范围进行操作。这些算法的效率可能比基于每个数据结构的算法的专门版本差得多,但是拥有通用版本意味着任何支持迭代器的新容器都可以自动拥有许多可用的功能,而不仅仅是什么在界面中指定。

希望这会有所帮助!

【讨论】:

  • +1。是的,你说的肯定有帮助。 List 有一个 binarySearch 的事实实际上会伤害那些认为这会更快而不加考虑的新手,但实际上在应用于LinkedList 时会慢得多。因此,它可能会使初学者感到困惑,而不是提供好处。 :)
  • 此外,还有另一种可能性:如果您的 compareTo 方法太慢以至于它实际上超过了遍历 LinkedList 所需的时间怎么办?这并非不可能,在这些情况下,Collections.binarySearch 实际上可能会胜过顺序搜索,即使是 LinkedList。
  • @LouisWasserman- 这是一个很好的观点。感谢您提出!
  • +1 以获得很好的解释。如果列表不是随机访问,我没有意识到还有备用算法。
【解决方案2】:

是的,你是对的,如果一个列表不提供随机访问,LinkedList 就是这种情况,没有任何优势。来自Collections.binarySearch()的javadoc:

此方法在 log(n) 时间内运行,用于“随机访问”列表(提供接近恒定时间的位置访问)。如果指定的列表没有实现 {@link RandomAccess} 接口并且很大,则此方法将执行基于迭代器的二分查找,执行 O(n) 链接遍历和 O(log n) 元素比较。

因此,这种情况下的复杂性将与顺序比较的情况相同 - O(n)。实际上,我相信在许多情况下顺序比较可能会更快。

【讨论】:

  • 评论你的“优势不大”。我会说在许多情况下,即使渐近复杂度相同,binarySearch 的实际性能也比顺序比较差。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
  • 2017-09-25
  • 1970-01-01
  • 2022-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多