Java中如何高效地去确定一个Array中是否包含了某个值
怎么去一个数组(没有排序)是否包含了一个值,这在Java一个非常频繁、有用的操作。这在Stack Overflow中也是被提问量最高的问题之一。根据问题的赞最高的回答显示,这个问题可以有好几种不同的算法,但是算法的复杂度是不同的。接下来,我将会展示每种方法的算法复杂度
1.1 四中不同的方法去检查一个Array钟是否包含了某个值
1) 使用List:
public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
2)使用Set:
public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}
3)使用一个简单的循环
public static boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
4)使用Array.binarySearch():*下面的代码是错的,数组是已经被完成了排序,因为binarySearch()只能用于已经被排序好的数组,你可以看到使用下面的代码得到的结果非常怪异
public static boolean useArraysBinarySearch(String[] arr, String targetValue)
{
int a = Arrays.binarySearch(arr, targetValue);
if(a > 0)
return true;
else
return false;
}
1.2 时间复杂度
大约的时间开销可以使用下面的代码获取。基本的思路就是使用一个大小为5、1K、10K的数组去查找,这种方法可能不是特别精确,但是这个思路非常简单
数组大小为5:
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
数组大小为1000:
String[] arr = new String[1000];
Random s = new Random();
for(int i=0; i< 1000; i++){
arr[i] = String.valueOf(s.nextInt());
}
结果:
useList: 112
useSet: 2055
useLoop: 99
useArrayBinary: 12
数组大小为10000:
String[] arr = new String[10000];
Random s = new Random();
for(int i=0; i< 10000; i++){
arr[i] = String.valueOf(s.nextInt());
}
结果:
useList: 1590
useSet: 23819
useLoop: 1526
useArrayBinary: 12
结果很清楚,使用简单的循环比使用collection效率更高,许多开发者喜欢使用List,但是效率并没有简单循环高。在对collection操作之前,需要将数组的内容push到collection中,这就需要将数组中所有的元素都读一遍。
如果使用userArrayBinary()方法,就需要将数组进行排序,但是实际情况中,很多数组都没有排序,那么就不能使用这个方法。
事实上,如果你真的需要检查一个数组/集合是否包含一个值,一个排序过得List或者tree可以在时间复杂度为O(log(n))内搞定它,或者使用hashset,时间复杂度为O(1)