在java中,我們如何判斷一個未排序數組中是否包含一個特定的值?這在java中是一個頻繁非常實用的操作。那么什么樣的方法才是最高效的方式?當然
,這個問題在Stack Overflow也是得票率非常高的一個問答。得票率排在最前的幾個答案給出集中不同的方法,但是他們的時間復雜度卻相差甚遠。
本文將詳細的探討主流的方法,並給出他們各自的時間損耗。
四種方法
List
public static boolean useList(String[] arr,String value){
return Arrays.asList(arr).contains(value);
}
Set
public static boolean useSet(String[] arr,String value){
return sets.contains(value)
}
loop
public static boolean useLoop(String[] arr,String value){
for(String s:arr){
if(s.equals(value))
return true;
}
return false;
}
binarySearch
public static boolean useBinarySearch(String[] arr,String value){
int result=Arrays.binarySearch(arr,value);
if(result>0)
return true;
else
return false;
}
此方法是不正確的,因為Arrays的binarySearch方法必須應用於有序數組。
性能對比
如果讀者熟悉以上java代碼片段中出現的集中數據結構,那么可以利用時間復雜度計算標准,
先推算這四種方式的性能對比的大致結果。當然,我們這里不采用這種方式,而是直接運用
如下測試代碼對比這四種方式的時間損耗情況。為了使得我們的測試結果更具有代表性,我們
針對不同的數據量做了多組測試。也許,這個測量方式並不精確,但是測量結果是清晰和可
信任的。測試的示例代碼如下:
public static void main(String[] args) {
String[] arr = new String[] { “www.”, “tiantian”, “bian”, “ma”, “.com”};
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
// use list
useList(arr, “天天編碼”);
// use set
//useSet(arr, “天天編碼”);
// use loop
//useLoop(arr, “天天編碼”);
// use binarySearch
//useBinarySearch(arr, “天天編碼”);
long endTime = System.nanoTime();
long duration = endTime = startTime;
System.out.pri}
數組長度 方法 運行耗時 數組長度 方法 運行耗時
5 list 13 100 list 50
5 set 72 100 set 668
5 loop 5 100 loop 47
5 binarySearch 100 inarySearch 8
1k list 112 10k list 1590
1k set 2055 10k set 23819
1k loop 99 10k loop 1526
1k binarySearch 12 10k binarySearch 12
總結
參照這個表格,結論已經很明顯了。最簡單的Loop方法比其他任何使用集合容器的方法都更加高效。
很多的開源項目代碼顯示,很多Java開發者喜歡使用第一種方法(list),實際上,該方法的性能並不好。
該方法把一個數組的元素轉移到一個新的集合容器中,顯然,在所有的元素轉移完成之前,新的集合容器處於不可用的狀態。
該表格還反映出一個事實:Arrays.binarySearch()方法的性能是最好的,特別是對於數組長度很大的數組。
但是該方法要求數組必須有序,這限制住了該方法的使用場景,本文實例代碼中的數組並不是有序的,
所以不應該使用該方法。
實際上,如果你確實需要高效地檢查某個特定值是否被包含在某些數組或者集合容器中,
你應該考慮使用有序列表或有序樹,這些集合容器查找特定值的時間復雜度是 O(log(n))。
當然,如果使用哈希集合,時間復雜度下降為 O(1)。