二分查找又叫折半查找,要查找的前提是檢索結果位於已排序的列表中。
概念
在一個已排序的數組seq中,使用二分查找v,假如這個數組的范圍是[low...high],我們要的v就在這個范圍里。查找的方法是拿low到high的正中間的值,我們假設是m,來跟v相比,如果m>v,說明我們要查找的v在前數組seq的前半部,否則就在后半部。無論是在前半部還是后半部,將那部分再次折半查找,重復這個過程,知道查找到v值所在的地方。
實現二分查找可以用循環,也可以遞歸,先給出兩種方式的偽代碼。
偽代碼
使用循環實現
Iterative-Binary-Search(seq, v, low, high)
while low <= high
mid = (low + high) / 2
if v == seq[mid]
return mid
elseif v > seq[mid]
low = mid + 1
else
high = mid - 1
return NIL
使用遞歸實現
Recursive-Binary-Search(seq, v, low, high)
if low > high
return NIL
mid = (low + high) / 2
if v == seq[mid]
return mid
elseif v > seq[mid]
return Recursive-Binary-Search(seq,v,mid+1,high)
else
return Recursive-Binary-Search(seq,v,low,mid-1)
無論是循環還是遞歸,當數組為空的時候就結束(low > high),返回空值。當查找到v值的時候,也立即結束。
Python版
使用循環實現
def search(seq, v, low, high):
while low <= high:
mid = (low + high) // 2
if v == seq[mid]:
return mid
elif v > seq[mid]:
low = mid + 1
else:
high = mid - 1
return None
使用遞歸實現
def search2(seq, v, low , high):
if low > high:
return None
mid = (low + high) // 2
if v == seq[mid]:
return mid
elif v > seq[mid]:
return search2(seq, v, mid + 1, high)
else:
return search2(seq, v, low, mid - 1)
Python版源碼: Github-Syler-Fun-Search-Python
Java版
使用循環實現
public static int search(int[] seq, int v, int low, int high) {
while (low <= high) {
int mid = (low + high) / 2;
if (v == seq[mid]) {
return mid;
} else if (v > seq[mid]) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return Integer.MIN_VALUE;
}
使用遞歸實現
public static int search2(int[] seq, int v, int low, int high) {
if (low > high) {
return Integer.MIN_VALUE;
}
int mid = (low + high) / 2;
if (v == seq[mid]) {
return mid;
} else if (v > seq[mid]) {
return search2(seq, v, mid + 1, high);
} else {
return search2(seq, v, low, mid - 1);
}
}
Java版源碼: Github-Syler-Fun-Search-Java
但是實際上呢,Java版應該寫成這個樣子
Arrays.binarySearch(int[] a, int fromIndex, int toIndex, int key)
Java源碼中的二分查找是這個樣子的:
public static int binarySearch(int[] a, int fromIndex, int toIndex,
int key) {
rangeCheck(a.length, fromIndex, toIndex);
return binarySearch0(a, fromIndex, toIndex, key);
}
// Like public version, but without range checks.
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
所以呢,Java里就不用寫二分查找算法,用自帶的吧。