比如現在有個記錄名單的字典,裏面的名字是按A-Z的順序排好的,現在我想找Lily這個人。我可以從第一頁開始一頁一頁的翻,但顯然這樣效率太低了。我可以怎麼做呢?首先我直接翻到字典的中間位置,假如發現這裏是字母H開頭的,那麼由於字典順序是排好的,我就可以斷定Lily肯定在後半本書裏,前半本我就可以不看了。接着我翻到後半本書的中間,發現是字母N開頭,那麼我就可以斷定,Lily是在這後半本書的前1/2裏。依次類推,用不了幾次,我就能找到Lily了。
以上所用的就是今天要說的二分查找法,可以看出,效率比一頁一頁的翻提高了太多。但這裏我們也需要注意一點就是,我們之所以可以用這個方法查找Lily,是因爲字典中的名字是排好序的,如果是亂序,用這種方法肯定就不行了。
這裏我們以一個有序的數列來介紹這個查找法:比如要查找62這個數。
[3 17 21 37 45 52 62 78 83 95]
我們記錄一個最高位95下標爲9,最低位3下標爲0,中間位下標=(最低位+最高位)/2取整,即爲4.然後我們去中間位的數,也即下標爲4對應的數45,由於45小於62,我們讓最低位=中間位+1,也就是5,這樣能重寫中間位爲(5+9)/2=7,也就取得了7對應的數78,78大於62,我們讓最高位=中間位-1,也就是6,這樣重寫取中間位(5+6)/2=5,這樣又取到了52,小於62,重寫計算最低位爲6,此時最高位等於最低位了,就得到了我們要的最終的值。當然如果在上一步計算的中間值正好是我們要的62,就講這個數拿出就可了。
語言顯得囉嗦且不一定能看懂,還是看代碼吧:
package com.cloud.algorithm; public class TestBinarySearch { public static int binarySearch(int[] arr,int dest){ int lower = 0; int upper = arr.length; while (lower <= upper) { int mid = (lower + upper) / 2; if (arr[mid] < dest) { lower = mid + 1; } else if (arr[mid] > dest) { upper = mid - 1; }else { return mid; } } return -1; } public static void main(String[] args) { int[] niArr = { 3, 17, 21, 37, 45, 52, 62, 78, 83, 95 }; int niDestIndex = binarySearch(niArr, 62); if(niDestIndex==-1){ System.out.println("沒找到"); }else{ System.out.println("下標爲:"+niDestIndex); } } }
其實對於java而已,已經爲我們封裝太多的功能,提供了大量的算法:
package com.cloud.algorithm; import java.util.Arrays; public class TestArrays { public static void main(String[] args) { int[] niArr = { 78, 83, 17, 45, 52, 21, 3, 37, 62, 95 }; // 將亂序的數組升序排列 Arrays.sort(niArr); // 格式化輸出排好序的數組 System.out.println(Arrays.toString(niArr)); // 在指定排好序數組中按照二分查找法查找某元素的下標 int niIndex = Arrays.binarySearch(niArr, 62); System.out.println("所查元素下標爲:"+niIndex); } }