1. 程式人生 > >插值查詢

插值查詢

在介紹插值查詢之前,首先考慮一個問題,為什麼二分查詢演算法中一定是折半,而不是折四分之一,或者折更多呢?
打個比方,在英文字典裡面查“apple”,你下意識翻開字典是翻前面的書頁還是後面的書頁呢?如果再查“zoo”,又該怎麼查呢?很顯然,這兩個單詞絕對不會從中間開始查起,而是有一定目的地從前或從後開始查;
同樣地,比如要在取值範圍1~10000之間100個元素從小到大均勻分佈的陣列中查詢5,我們自然會考慮從陣列下標較小的開始查詢;
經過以上分析,二分查詢這種查詢方式,不是自適應的(也就是傻瓜式的),二分查詢中查詢點計算如下:
mid = (low + high)/2 = low + 1/2 * (high - low);
通過類比,可以將查詢的點改進為如下:
mid = low + ((key - arr[low])/(arr[high] - arr[low])) * (high - low);
也就是將上述的比例引數1/2改進為自適應的,根據關鍵字在整個有序表中所處的位置,讓mid值的變化更靠近關鍵字key,這樣也就間接地減少了比較次數;

基本思想:基於二分查詢演算法,將查詢點的選擇改進為自適應選擇,可以提高查詢效率。當然,插值查詢也屬於有序查詢。

注:對於表長較大,而關鍵字分佈又比較均勻的查詢表來說,插值查詢演算法的平均效能比二分查詢演算法要好得多。

複雜度分析:時間複雜度O(log2^(log2^n))。

程式碼示例:
public class Test {

    public static void main(String[] args) {
        
        int[] arr = {1, 2, 3, 6, 8, 9};
        System.out.println(binary_Search(arr, 8));
    }
    public static int binary_Search(int[] arr, int num) {
        int high = arr.length - 1;
        int low = 0;
        int mid;
        while(low < high) {
            mid = low + ((num - arr[low])/(arr[high] - arr[low])) * (high - low);
            if(arr[mid] > num) {
                high = mid - 1;
            } else if (arr[mid] < num) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}