contains与binarySearch的性能比较

查找List中的元素有两种方法,一个是使用contains()方法,还有一个是使用Collectoins.binarySearch()。binarySearch()方法有两种实现,一个版本是接受List和Comparator对象作为参数,另一个是接受List以及Comparable对象。这个方法使用二分查找算法来查询指定列表中的某个元素。在调用这个方法前,列表中的元素得按照它们的自然顺序进行升序排列。如果列表没有排序的话,方法调用的结果是不确定的。如果列表有多个元素与查找的元素一样,那么返回的具体是哪一个是不确定的。对于一个可”随机访问“的列表来说,算法的时间复杂度是O(log(n)。如果指定的列表没有实现RandomAccess接口并且列表长度很大的话,这个方法会基于迭代器来进行二分法的查找,它会执行O(n)次链接的遍历以及O(log n)次元素的比较。在方法的结尾,如果查找到了该元素,则返回对应元素在列表中的序号,否则返回的是(-(插入点序号)-1)。插入点的意思是这个元素应该在这个列表中的这个位置进行插入:第一个大于该查找元素的值所在的位置,如果所有元素都小于它的话则是list.size()。这意味着,当且仅当元素查找成功时,返回值才会大于等于0。List接口常见的实现比如ArrayList, Vector, CopyOnWriteArrayList和Stack都实现了RandomAccess接口,它们可以用来进行二分查找,不过还有些别的实现比如LinkedList,它没有实现RandomAccess接口,因此不适合使用二分查找。由于二分查找只能在排好序的列表中进行,因为在查找前你得先对列表排序,这可能会影响到性能,尤其是你的列表很大并且本来就无序的情况下。

下面是一段使用二分法来查找对象的程序。我们有一个包含1百万个整数的列表,这里同时使用contains()及binarySearch()方法进行搜索。



import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** * Java program to perform binary search in Java collection e.g List, Set
[*] @author Javin Paul
[*]/
public class BinarySearchTest {
public static final Logger logger = LoggerFactory.getLogger(BinarySearchTest.class);

public static void main(String args[]) {
//creating List
List<Integer> numbers = new ArrayList<Integer>(1000000); //List of 1M records

//initializing List
for(int i =0; i<numbers.size(); i++){
numbers.add(new Integer(i));
}

//performing contains search
long startTime = System.nanoTime();
boolean isExist = numbers.contains(new Integer(1000000));
long totalTime = System.nanoTime() - startTime;
logger.info("Time to search 1Mth Record using contains() is {} nano seconds", totalTime);

//performing binary search
startTime = System.nanoTime();
Collections.sort(numbers); // List needs to be sorted for Binary Search
Integer number = Collections.binarySearch(numbers, new Integer(1000000));
totalTime = System.nanoTime() - startTime;
logger.info("Time to search 1Mth Record using binary search is {} nano seconds", totalTime);
}
}



输出结果:


2013-06-04 23:23:17,834 0 [main] INFO test.BinarySearchTest - Time to search 1Mth Record using contains() is 51404 nano seconds
2013-06-04 23:23:17,849 15 [main] INFO test.BinarySearchTest - Time to search 1Mth Record using binary search is 554261 nano seconds


从结果中可以看到,contains()方法比二分法要快了10倍,这说明使用contains()方法来搜索列表中的元素非常有效,尤其是当列表实现了RandomAccess接口的情况下。

译注:作者这么说似乎不太公平,如果列表原本就有序的话,二分查找还是相当快的,这里他是加上了排序的时间。如果排序后能进行重复利用,也还是比较划算的。

感谢网友风云无浪指出的问题,其实文中程序的列表是空的。不过修改完后该程序运行的结果仍然是相差大概10倍。当然了,这还是因为算上了排序的时间,毕竟单独从搜索的效率来说的话,二分法通常来说肯定是比顺序查找要快的。


原创文章转载请注明出处:[url=http://it.deepinmind.com/%E6%80%A7%E8%83%BD/2014/05/11/binary-search-vs-contains-performance.html]http://it.deepinmind.com[/url]
[url=http://javarevisited.blogspot.sg/2014/03/binary-search-vs-contains-performance.html]英文原文链接[/url]
<think>好的,我现在需要处理用户关于Javacontains方法的问题。首先,用户希望了解contains方法的使用说明示例。根据提供的引用内容,引用1到4都涉及到contains方法在Java中的用法,特别是不同的集合类中的应用。 首先,我应该确定contains方法的基本定义。根据引用1,contains方法是用于判断集合中是否包含特定元素的方法,属于java.util包中的集合类如ArrayList、HashSet等的常用方法。需要明确说明它的返回类型是boolean,参数是Object类型。 接下来,需要分点说明不同集合类中的contains方法。比如ArrayList基于equals方法判断元素是否存在,而HashSet则依赖hashCodeequals方法。这部分需要详细说明两者的区别,因为用户可能不清楚不同集合的实现差异。 然后,考虑用户可能需要示例代码。引用2、3、4都提到了示例,但用户提供的引用内容中没有具体代码。不过根据常见知识,可以构造ArrayListHashSet的示例,展示contains的使用。例如,创建一个ArrayList,添加元素,然后调用contains检查是否存在。同样适用于HashSet,并指出其高效性。 还需要注意点,比如对象的equalshashCode方法正确重写的重要性,特别是对于自定义对象。如果用户使用自定义类,而没有正确重写这些方法,contains可能无法正确工作。这部分需要强调,避免常见错误。 此外,性能方面的考虑,比如ArrayListcontains是O(n),而HashSet是O(1),这会影响在不同场景下的选择。用户可能关心如何优化性能,所以需要提及这一点。 最后,总结contains方法的应用场景,比如快速查找、数据校验等,帮助用户理解何时使用该方法。可能还需要提醒用户注意null值的处理,不同集合对null的支持情况。 检查是否有遗漏的信息,比如参数是否为null时的行为,或者集合类如LinkedList的情况。根据引用1,LinkedList也属于提到的集合类,所以可能需要简要说明LinkedListcontains方法同样基于equals方法,性能也是O(n)。 确保回答结构清晰,分点说明,并给出示例代码。需要按照用户的要求,使用中文,行内公式正确(虽然这个问题可能不涉及数学公式,但保持格式正确),独立公式单独成段。不过当前问题可能不需要数学公式,所以可能不需要处理这部分。 最后生成相关问题,考虑用户可能进一步想了解如何优化contains性能,或者比较不同集合的contains效率,或者如何正确重写equalshashCode方法。例如: 1. 如何提高ArrayListcontains方法效率? 2. 为什么HashSet的contains方法比ArrayList快? 3. 自定义对象如何使用contains方法? 确保引用标记正确,引用1到4虽然内容重复,但需要正确对应到回答中的点,比如引用1提到contains的用途不同集合类,引用2-4可能涉及示例,但用户提供的引用内容中示例部分没有具体代码,所以可能需要自行构造示例,并在末尾添加引用标识。</think>### Javacontains方法使用说明 在Java中,`contains()` 方法用于判断集合中是否包含指定元素,返回值为布尔类型(`true`/`false`)。它是`java.util.Collection`接口定义的方法,被所有集合类(如`ArrayList`、`HashSet`、`LinkedList`等)实现。以下是详细说明及示例: --- #### 1. **方法定义** - **语法**:`boolean contains(Object o)` - **参数**:`Object o`(待检查的元素) - **返回值**:若集合包含该元素,返回`true`;否则返回`false`。 --- #### 2. **不同集合类的实现差异** - **`ArrayList`/`LinkedList`** 通过遍历元素并调用`equals()`方法逐个比较,时间复杂度为$O(n)$[^1]。 示例: ```java ArrayList<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); System.out.println(list.contains("apple")); // true System.out.println(list.contains("orange")); // false ``` - **`HashSet`/`HashMap`** 基于哈希表实现,通过`hashCode()`快速定位元素,再调用`equals()`验证,时间复杂度为$O(1)$。 示例: ```java HashSet<Integer> set = new HashSet<>(); set.add(10); set.add(20); System.out.println(set.contains(10)); // true ``` --- #### 3. **关键注意事项** - **对象必须正确重写`equals()``hashCode()`** 若集合存储自定义对象,需确保这两个方法被正确重写,否则`contains()`可能无法正确判断。 示例: ```java class Student { String name; int id; @Override public boolean equals(Object obj) { if (obj instanceof Student) { return this.id == ((Student) obj).id; } return false; } @Override public int hashCode() { return Objects.hash(id); } } HashSet<Student> students = new HashSet<>(); students.add(new Student("Alice", 1)); System.out.println(students.contains(new Student("Bob", 1))); // true(因为id相同) ``` - **`null`值的处理** 大部分集合类允许存储`null`,但需注意具体实现。例如,`HashSet`允许一个`null`元素,而`TreeSet`会抛出`NullPointerException`。 --- #### 4. **性能优化建议** - 频繁使用`contains()`时,优先选择`HashSet`或`HashMap`,避免使用`ArrayList`或`LinkedList`。 - 对已排序的列表,可通过二分查找(`Collections.binarySearch()`)替代`contains()`,时间复杂度降为$O(\log n)$。 --- #### 5. **典型应用场景** - **数据去重**:使用`HashSet`快速过滤重复元素。 - **权限校验**:检查用户是否在允许的列表中。 - **缓存查询**:判断缓存中是否存在目标数据。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值