二分查找法的思想很是簡單,對於一個有序數列,找它中間的元素,看是不是查找目標,若是不是,就看這個查找目標是小於仍是大於中間元素,而後在對應的區間內重複上述過程。java
須要注意幾個問題:git
while 循環:while 循環的條件應該是 left < right 仍是 left <= right 呢?github
target 和 arr[mid] 的判斷:當 target > arr[mid] 時,是應該 left = mid 仍是 left = mid + 1 呢?算法
private int binarySearch(T arr[], int n, T target) { int left = 0, right = n - 1; // 在 [left, right] 區間內尋找 target while (left <= right) { // 當 left = right 時,區間 [left, right] 仍然有效 int mid = (left + right) / 2; if (arr[mid] == target) return mid; if (target > arr[mid]) left = mid + 1; // target 在 [mid+1, r] 中 else right = mid - 1; // target 在 [left, mid - 1] 中 } return -1; }
不知道到這裏你們有沒有發現一個 bug 測試
由於 left 和 right 都是 int,因此當值足夠大時,在計算 mid = (left + right) / 2 時可能會發生整型溢出!code
所以,爲了不這個問題,咱們使用減法來計算。get
徹底正確的二分查找法it
public int binarySearch(T[] arr, int n, T target) { int left = 0, right = n - 1; // 在 [left, right] 區間內尋找 target while (left <= right) { // 當 left = right 時,區間 [left, right] 仍然有效 int mid = left + (right - left) / 2; if (arr[mid].compareTo(target) == 0) return mid; if (target.compareTo(arr[mid]) > 0) left = mid + 1; // target 在 [mid+1, r] 中 else right = mid - 1; // target 在 [left, mid - 1] 中 } return -1; }
咱們能夠寫一個 Util 來幫助咱們生成測試用例io
ArrayUtil.javaast
public static Integer[] generateSortedArray(int n) { assert n > 0; Integer[] arr = new Integer[n]; for (int i = 0; i < n; i++) { arr[i] = i; } return arr; }
BinarySearch.java
public static void main(String[] args) { BinarySearch<Integer> bs = new BinarySearch<Integer>(); int n = (int)Math.pow(10, 7); // 用 10,000,000 數據測試 Integer[] data = ArrayUtil.generateSortedArray(n); long startTime = System.currentTimeMillis(); for (int i = 0; i < n; i++) if (i != bs.binarySearch(data, n, i)) throw new IllegalStateException("find i failed"); long endTime = System.currentTimeMillis(); System.out.println("Binary Search success!"); System.out.println("Time cost: " + (endTime - startTime) + "ms"); }