Java List二分查找与contains性能对比
Java 提供了两个方法,即 Collections.binarySearch() 和 contains() 来寻找一个列表中的元素。在引擎盖下,contains()方法使用indexOf()方法来搜索元素。indexOf()方法在列表中线性循环,将每个元素与键进行比较,直到找到键为止,并返回真,否则当没有找到元素时返回假。Collections.binarySearch()的时间复杂度是O(log2(n))。但是如果我们想使用这个方法,那么列表应该是被排序的。如果列表没有被排序,那么我们需要在使用 Collections.binarySearch() 之前对其进行排序,这需要 O(nlog(n)) 的时间。
如何选择
- 如果要找的元素靠近列表的起始点,那么contains()方法的性能会更好,因为contains()从列表的起始点开始线性地搜索该元素。
- 如果元素被排序,并且元素的数量相对较大,那么 Collections.binarySearch() 就更快,因为它只需要 O(log2(n)) 的时间。
- 如果列表中的元素没有被排序,那么contains()方法的性能会更好,因为它只需要O(n)时间,但如果搜索查询的数量很高,那么Collections.binarySearch()方法的整体性能会更好,因为我们在第一次搜索时只对列表进行一次排序,需要O(nlog(n))时间,之后每次搜索操作需要O(log(n))时间。
- 对于一个包含相对较少元素的列表来说,contains()会产生更好的速度。
- 如果我们使用的LinkedList没有实现RandomAccess接口,因此无法提供O(1)时间来访问一个元素,那么我们应该选择contains()而不是Collections.binarySearch(),因为Collections.binary search()需要O(n)来进行链接遍历,然后需要O(log(n))时间来进行比较。
现在我们将讨论两种变体,即排序后的列表是
1.分类的小名单
2.分类的大名单
3.未分类列表
案例1:对于一个小型的排序列表
在下面提到的代码中,我们以一个只包含0到99的100个元素的排序列表为例,我们搜索了40个元素,正如我们在上面看到的,在小列表中,contains()在速度上比Collections.binarySearch有优势。
示例
输出
案例2:对于一个大的排序的列表
在下面提到的例子中,我们创建了一个排序的ArrayList,其中包含100000个从0到99999的元素,我们使用contains()和Collections.sort()方法在其中找到40000个元素。由于该列表是排序的,并且有相对较多的元素,Collections.sort()的性能比contains()方法更好。
示例
输出
案例3:对于一个未排序的列表
在下面提到的代码中,我们创建了一个未排序的ArrayList,在其中存储了0到100000之间的随机数字。由于该列表是未排序的,所以contains()方法的性能更好,因为它只需要O(n)时间,而使用Collections.sort()方法我们首先要对列表进行排序,这需要额外的O(nlog(n))时间,然后需要O(log2(n))时间来搜索该元素。
示例
输出