为什么在Java中列出二进制搜索?

时间:2012-01-15 22:56:35

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

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

我的理解是否正确?感谢。

2 个答案:

答案 0 :(得分:13)

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

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

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

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

希望这有帮助!

答案 1 :(得分:3)

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

  
    

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

  

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