二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。
使用二分查找的數據必須是有序的,數據結構一般是數組。
實現思想:
- 1 拿想要搜索的數去和有序數組的中位數比較,如果相等的話,就找到了。
- 2 如果中位數比較大,則從中位數左邊那一塊範圍繼續找,右邊的不用找了。找左邊的時候繼續與左邊那一塊的中位數比較。
- 3 如果中位數比較小,則從中位數右邊那一塊範圍繼續找,左邊的不用找了。找右邊的時候繼續與右邊那一塊的中位數比較。
- 4 重複123步,不斷地縮小範圍,直到找到爲止(即中位數等於要搜索的數),如果查找過程中出現左邊界的下標大於右邊界的下標,則說明數組中沒有要搜索的數。
類似的簡單例子:
張三買了一本30元的《算法入門到放棄》,讓李四從1-100之間猜書的價格(只能猜整數),張三不斷提示猜對了,或者是猜多了還是猜少了。
如果李四從1,2,3,4 ···開始猜,則要猜30次。如果從100, 99 , 98 ···開始猜,則要猜71次。但是李四很聰明,他是這樣猜的。
李四:50。
張三:不對,猜多了。
李四心想:“搜嘎,那就是在1-50之間咯~,哦不對,是1-49,再猜一箇中間的數”。
李四:25。
張三:不對哦,你猜少了。
李四:(那就是在25-49之間,不,是26-49之間),是37嗎?
張三:不是,猜多了。
李四:31?
張三:猜多了。
李四:28?
張三:猜少了。
李四:29?
張三:猜少了。
李四:知道了,30塊,哈哈。
張三:恭喜你,猜對啦。
由以上可知,聰明的李四用二分查找的思想,猜了7次就猜對了。
下面是java實現二分查找的代碼:
/*
*二分查找算法
* 使用條件:已經排好序的數組
* */
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,10,11,12,23,34,56,78,89};//示例數組
int target = 10; //搜索目標數
int result = binarySearch(arr, target); //調用搜索方法
System.out.println(result);
}
private static int binarySearch(int[] arr, int target){
int l = 0; //左邊界
int r = arr.length-1; //右邊界爲數組長度-1
int mid = l + (r - l) / 2; //有序數組的中位數,也可以寫成 mid = (r + l) / 2
while (arr[mid] != target){ //中位數不等於目標數
if (arr[mid] > target){
r = mid - 1; //目標在中位數的左側,縮小範圍
}
else {
l = mid + 1; //目標在中位數的右側,縮小範圍
}
if (l > r){
return -1; //搜索失敗,搜索範圍不斷縮小過程中,左邊界大於右邊界
}
//System.out.println(arr[l] + " " + arr[r]); //取消註釋可以查看每一次搜索時的查找範圍
mid = l + (r - l) / 2;
}
return arr[mid]; //搜索成功,返回搜索到的數
}
}
對於算法而言,解決問題的思想是精髓,語言不過是實現的工具而已,如果掌握了思想,趕快用自己熟悉的編程語言去試一試吧。
使用遞歸的方法也可以實現。
只是不太建議,當數組大的時候內存佔用會比較多。
public class BinarySearch2 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,10,11,12,23,34,56,78,89};
int target = 19; //搜索目標數
int l = 0; //左邊界
int r = arr.length-1; //右邊界爲數組長度-1
binarySearch(arr, l, r, target);//調用搜索函數
}
private static void binarySearch(int[] arr,int l, int r, int target){
int mid = l + (r - l) / 2; //有序數組的中位數
if (arr[mid] != target){ //中位數不等於目標數
if (arr[mid] > target){
r = mid - 1; //目標在中位數的左側,縮小範圍
}
else {
l = mid + 1; //目標在中位數的右側,縮小範圍
}
if (l > r){
System.out.println("fail to find the target");
return ;//搜索失敗,搜索範圍不斷縮小過程中,左邊界大於右邊界
}
// System.out.println(arr[l] + " " + arr[r]); //取消註釋可以查看每一次搜索時的查找範圍
binarySearch(arr, l, r, target); //遞歸調用
return ;
}
System.out.println("success! " + arr[mid]);
}
}