问:Java 中如何高效判断数组中是否包含特定值?
答:一般来说有四种方式,具体如下:
//使用List
public static boolean useList(String[] arr, String target) {
return Arrays.asList(arr).contains(target);
}
//使用Set
public static boolean useSet(String[] arr, String target) {
Set set = new HashSet(Arrays.asList(arr));
return set.contains(target);
}
//使用一个循环
public static boolean useLoop(String[] arr, String target) {
for(String s: arr){
if(s.equals(target))
return true;
}
return false;
}
//使用Arrays.binarySearch(),只能用于已排好序的数组中。
public static boolean useArraysBinarySearch(String[] arr, String target) {
int ret = Arrays.binarySearch(arr, target);
return (ret > 0);
}
有了上面四种判断方式后,我们可以进行时间复杂度测试,即给定一定量级的数据进行实测,当然,你也可以直接分析时间复杂度。测试样例如下:
public static void main(String[] args) {
String[] arr = new String[] {"CD", "BC", "EF", "DE", "AB"};
//use list
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useList(arr, "A");
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("useList: " + duration / 1000000);
//use set
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useSet(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useSet: " + duration / 1000000);
//use loop
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useLoop(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useLoop: " + duration / 1000000);
//use Arrays.binarySearch()
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useArraysBinarySearch(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useArrayBinary: " + duration / 1000000);
}
各种测试结果如下:
//结果
useList: 13
useSet: 72
useLoop: 5
useArraysBinarySearch: 9
//对于长度为1K的数组结果
useList: 112
useSet: 2055
useLoop: 99
useArrayBinary: 12
//对于长度为10K的数组结果
useList: 1590
useSet: 23819
useLoop: 1526
useArrayBinary: 12
通过测试很明显可以看出,使用简单循环的方法比使用其他任何集合效率更高。而许多开发者会使用第一种方法,但是它并不是高效的。因为将数组压入 Collection 类型中,需要首先将数组元素遍历一遍,然后再使用集合类做其他操作。如果使用 Arrays.binarySearch() 方法,数组必须是已排序的。由于上面的数组并没有进行排序,所以该方法不可使用。而实际上,如果你需要借助数组或者集合类高效地检查数组中是否包含特定值,一个已排序的列表或树可以做到时间复杂度为 O(log(n)),HashSet 可以达到 O(1)。