二分查詢的簡單理解

程式設計師翔仔發表於2022-07-04

詳細描述

二分查詢的搜尋過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜尋過程結束;如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,而且跟開始一樣從中間元素開始比較。如果在某一步驟陣列為空,則代表找不到。這種搜尋演算法每一次比較都使搜尋範圍縮小一半。

二分查詢詳細的執行步驟如下:

  1. 在有序表中,取中間記錄作為比較物件;
  2. 若給定值與中間記錄的關鍵字相等,則查詢成功;
  3. 若給定值小於中間記錄的關鍵字,則在中間記錄的左半區繼續查詢;
  4. 若給定值大於中間記錄的關鍵字,則在中間記錄的右半區繼續查詢;
  5. 不斷重複步驟 1~4,直到查詢成功,或所有查詢區域無記錄,查詢失敗為止。

演算法圖解

二分查詢

問題解疑

二分查詢演算法有哪些侷限性?

二分查詢演算法需要按照下標隨機訪問。所以更適合陣列結構,而不適合連結串列結構,陣列按照下標隨機訪問資料的時間複雜度是 \(O(1)\),而連結串列隨機訪問的時間複雜度是 \(O(n)\)

二分查詢針對的是有序數。二分查詢只能用在插入、刪除操作不頻繁,一次排序多次查詢的場景中,針對動態變化的資料集合,二分查詢將不再適用。

資料量太小不適合二分查詢。在一個大小為 10 的陣列中查詢一個元素,不管用二分查詢還是順序遍歷,查詢速度都差不多,只有資料量比較大的時候,二分查詢的優勢才會比較明顯。

資料量太大也不適合二分查詢。二分查詢是作用在陣列這種資料結構之上的,太大的資料用陣列儲存比較吃力,也就不能用二分查詢了。

二分查詢演算法有哪些變形?

  • 查詢第一個值等於給定值的元素
  • 查詢最後一個值等於給定值的元素
  • 查詢第一個大於等於給定值的元素
  • 查詢最後一個小於等於給定值的元素

程式碼實現

查詢介面

package cn.fatedeity.algorithm.search;

public interface Search {
    int search(int[] numbers, int target);
}

二分查詢類

package cn.fatedeity.algorithm.search;

/**
 * 二分查詢類
 */
public class BinarySearch implements Search {
    private int search(int[] numbers, int target, int left, int right) {
        if (left > right) {
            return -1;
        } else if (left == right) {
            if (numbers[left] == target) {
                return left;
            } else {
                return -1;
            }
        }
        if (target < numbers[left] || target > numbers[right]) {
            return -1;
        }

        int mid = (left + right) >> 1;
        if (numbers[mid] > target) {
            return this.search(numbers, target, left, mid - 1);
        } else if (numbers[mid] < target) {
            return this.search(numbers, target, mid + 1, right);
        } else {
            return mid;
        }
    }

    @Override
    public int search(int[] numbers, int target) {
        return this.search(numbers, target, 0, numbers.length - 1);
    }
}

相關文章