[英]A timer for seeing how long an algorithm is taking is saying my binary search takes longer than a linear search
這是關於要點的課程https://gist.github.com/2605302
我已經使用不同的文件對它進行了多次測試,即使對二進制搜索進行的比較較少,所以花費的時間總是更多。 出了什么問題?
public static int linerSearch ( String array [], String word, long resultsArray [])
{
int comparisons = 0;
int pos = -1;
//i have started the timer where the search actualy starts
long start = System.nanoTime ();
for (int i = 0; i < array.length; i++){
comparisons = comparisons + 1;
if (array [i].equals (word)){
pos = i;
break;
}
}
long stop = System.nanoTime ();
long total = stop - start;
resultsArray [0] = total;
resultsArray [1] = (long) (long) array.length;
resultsArray [2]= (long) (long) comparisons;
return pos;
}
這是下一個binarySearch類
public static int binarySearch (String [] array, String word, resultsArray []) {
int start = 0;
int end = array.length - 1;;
int midPt;
int pos = -1;
int comparisons2 = 0;
long start2 = System.nanoTime ();
Arrays.sort (array);
while (start <= end) {
midPt = (start + end) / 2;
comparisons2 = comparisons2 + 1;
if (array [midPt].equalsIgnoreCase (word)) {
pos = midPt;
break;
}
else if (array [midPt].compareToIgnoreCase (word) < 0) {
start = midPt + 1;
comparisons2 = comparisons2 + 1;
//camparisons2 addition was added inside this elseif and other elseif as a work around for not breaking the elseif statement tree, if it has made it two the last elseif then two camparisons after the first one will have been done
} else if (array [midPt].compareToIgnoreCase (word) > 0) {
comparisons2 = comparisons2 + 2;
end = midPt - 1;
}
}
long stop2 = System.nanoTime ();
long total2 = stop2 - start2;
resultsArray [0] = total2;
resultsArray [1] = (long) (long) array.length;
resultsArray [2]= (long) (long) comparisons2;
return pos;
}
編輯:我還應該補充一點,我在一個已經排序過的數組上嘗試了它,沒有那行代碼,它仍然是一個更長的時間,它不應該
您的基准測試的問題是Arrays.sort(數組)花費大部分時間並且不計算它的比較。 線性搜索需要N次比較。 排序數組時,您需要花費超過N次比較。
要查看二進制搜索速度更快,您應該進行此類測試:
1)使用線性搜索搜索1000次不同的元素
2)對數組進行一次排序,並使用二進制搜索1000次搜索不同的元素
您的基准存在缺陷,原因有很多:
我還沒有驗證你的二進制搜索算法是否正確,但為什么不使用與JDK捆綁的那個(在java.util.Arrays類中)。
無論如何,你不需要測量任何東西。 平均而言,二進制搜索比線性搜索更快。 無需再證明這一點。
好的,我已經為你一勞永逸地解決了這個問題。 首先,這是我使用的二進制搜索方法:
public static int binarySearch(String[] array, String word, long resultsArray[]) {
int start = 0;
int end = array.length - 1;
int midPt;
int pos = -1;
int comparisons2 = 0;
//Arrays.sort(array);
long start2 = System.nanoTime();
while (start <= end) {
midPt = (start + end) / 2;
int comparisonResult = array[midPt].compareToIgnoreCase(word);
comparisons2++;
if (comparisonResult == 0) {
pos = midPt;
break;
} else if (comparisonResult < 0) {
start = midPt + 1;
} else { // comparisonResult > 0
end = midPt - 1;
}
}
long stop2 = System.nanoTime();
long total2 = stop2 - start2;
resultsArray[0] = total2;
resultsArray[1] = (long) array.length;
resultsArray[2] = (long) comparisons2;
return pos;
}
您會注意到我通過保存比較結果並使用它來減少比較次數。
接下來,我下載了這個235882字的列表 。 它已經被排序而忽略了這種情況。 然后,我構建了一個測試方法,將該文件的內容加載到一個數組中,然后使用這兩種搜索方法查找該列表的每個單詞。 然后,它分別平均每種方法的比較次數和次數。
我發現你必須小心選擇使用哪種比較方法: 如果你使用Arrays.sort(...)
列表並在二進制搜索中使用compareToIgnoreCase
,它就會失敗! 失敗我的意思是它找不到給定列表中的單詞,即使該單詞實際存在於那里。 這是因為Arrays.sort(...)
是一個區分大小寫的字符串排序器。 如果使用它,則必須使用compareTo(...)
方法。
所以,我們有兩個案例
compareToIgnoreCase
的使用 compareTo
的使用 除了二進制搜索中的這些選項之外,您還可以在線性搜索中使用選項:是使用equals
還是使用equalsIgnoreCase
。 我對所有這些案例進行了測試並對它們進行了比較。 平均結果:
equals
線性搜索:時間:725536 ns; 比較:117941; 時間/比較:6.15 ns equalsIgnoreCase
線性搜索:時間:1064334 ns; 比較:117940; 時間/比較:9.02 ns compareToIgnoreCase
二進制搜索:時間:1619 ns; 比較:16; 時間/比較:101.19 ns compareTo
二進制搜索:時間:763 ns; 比較:16; 時間/比較:47.69 ns 所以,現在我們可以清楚地看到你的問題: compareToIgnoreCase
方法花費的時間是equals
方法的16倍! 因為平均而言,需要二元搜索16比較才能找到給定的單詞,因此您可以在此時執行124次線性比較。 因此,如果您使用比這更短的單詞列表進行測試,則線性搜索確實總是比二進制搜索更快,因為它們使用的方法不同。
實際上,我還計算了線性搜索能夠比二進制搜索更快找到的單詞數:164使用compareTo
方法時,使用compareToIgnoreCase
方法時為614。 在235882個單詞的列表中,這個數字約為0.3%。 總而言之,我認為二進制搜索比線性搜索更快仍然是安全的。 :)
在你問之前的最后一點:我從binarySearch
方法中刪除了排序代碼,因為這實際上是完全不同的東西。 由於您正在比較兩種搜索算法,如果您將排序算法的成本添加到其數字中,則對另一種搜索算法不公平。 我已經在另一個答案中發布了以下評論作為評論,但為了完整起見,我將在此處復制:
二進制搜索會增加排序的開銷成本。 因此,如果您只需要從數組中找到一個元素,則線性搜索總是更快,因為排序至少需要O(n log n)時間,然后二進制搜索需要O(log n)時間,由O(n)控制記錄n)操作。 線性搜索在O(n)時間內執行,該時間優於O(n log n)。 但是一旦你對數組進行了排序,O(log n)就好於O(n)。
如果你堅持在binarySearch
方法中使用排序命令,你應該知道,通過我的設置排序,初始隨機順序中的長字列表平均需要超過140000000 ns或0.14秒。 在這段時間里,你可以執行使用一些23000000比較equals
的方法,所以你如果)你的陣列是一個隨機的順序, 真的 不應該使用二進制搜索b)如果你只輩子必須找個只是一個或幾個元素那里。
還有一件事。 在此示例中,您在String數組中搜索單詞時,訪問數組中項目的成本可以忽略不計,因為該數組保存在計算機的快速主內存中。 但是,如果你有,說,下令文件的一個巨大的一堆和你試圖找到他們的東西,然后訪問一個文件將盡一切其他計算的成本可以忽略不計,而不是成本。 所以二元搜索在這種情況下也會完全搖擺不定。
您的代碼不會測量二進制搜索,也會在搜索之前對數組進行排序。 這將始終比簡單的線性搜索更長。
} else if (array [midPt].compareToIgnoreCase (word) > 0) {
你根本不需要這個測試。 在代碼的這一點上,沒有其他可能性。 它並不平等,它不低於:你已經測試過了; 所以它必須大於。
因此,您可以將比較減少33%。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.