我所知道查找算法之插值查找

做者前言

你們好,我是阿濠,今篇內容跟你們分享的是查找算法之插值查找法,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.

二分查找算法根據折半進行查找,可是還能根據二分查找進行優化嗎算法

假設咱們如今有數組arr={1,2,3,4,5,6,7,8,10,11,12},咱們使用二分法查找:1segmentfault

那麼根據特性執行會執行幾回操做:先是找到中間值二分再進行二分...數組

那麼能不能經過自適應的方案快速定位到須要查找的值呢app

那麼就可使用插值查找算法性能

1、插值查找法的介紹

插值查找原理介紹:

1.插值查找算法相似於二分查找不一樣的是插值查找每次從自適應mid處開始查找。學習

2.將折半查找中求mid索引的公式進行優化key 表明查找的值findValue優化

clipboard.png

公式爲:int midIndex = low + (high - low) * (key - arr[low]) / (arr[high]- arr[low]);spa

對應代碼:int mid= left+(right-left) *(findvalue -arr[left])/ (arr[right]-arr[left])code

2、算法思路解析

二分查找法爲何是 left + right / 2 呢?

由於二分法查找的思想基於數組的有序性,每次都將當前的數組分爲兩半,經過關鍵字和中間元素的比較,當即排除掉其中不可能存在和鍵值相等的元素的那一半blog

因此使用經過 left + right / 2,並比較Keyarr[mid]大小,丟掉"一半的元素"

(從 left + right / 2 能夠看出被排除的一半元素不會歸入到下一次的比較中了)

插值查找爲何是(findvalue-arr[left])/(arr[right]-arr[left])

首先咱們根據基於數組的有序性,想想查找的位置必定要從中間開始查找嗎

打個比方:咱們在一本英文字典裏查找apple這個單詞的時候, 你確定不會從字典中間開始查找, 而是從字典開頭部分開始翻,由於以爲這樣的找法纔是比較快的。

那麼爲何你會從頭部分開始翻呢?由於知道字典按照字母有序排序的,而且apple這個單詞是a開頭,因此從頭開始翻,對嘛?

那麼這時就有了一個思路: 若是能在查找前準確地預測關鍵字在數組中的位置的話,這樣的查找方法能比二分查找提升更多的性能

因此根據差值公式( key - arr[low]) / (arr[high] -arr[low]),將要查找的關鍵字 key 與查找表中的最大、最小記錄的關鍵字比較的查找方法。

3、經過應用示例認識插值查找算法

舉例:有一數組arr=[1,2,3,4,5,6,7,8......100] 假設咱們須要查找的值爲:1

按照二分法查找:須要 mid = (left + right ) / 2折半...再折半...才找到1

按照插值查找算法

int mid = left+(right-left) \* (findvalue -arr[left]) / (arr[right]-arr[left])

對應的代碼:int mid= 0+(99-0) * (1- 1) / (100-1) = 0+99 * 0 / 99 = 0 直接找到值:1

好比咱們查找的值爲:100

對應的代碼:int mid=0 + (99-0) * (100-1) /(100-1)= 0+99 * 99/99 = 0+99=99

/**
 * @param arr 數組
 * @param left 左邊索引
 * @param right 右邊索引
 * @param  findValue 查找值
 * @return 若是找到則返回對應的下標,沒有找到返回-1 便可
 */
//編寫插值查找方法
public static  int insertValueSearch(int[] arr,int left,int right,int findValue){
    //1、沒有找到的狀況或者查找的值(小於數組最小值或者大於數組最大值)
    if(left>right||findValue<arr[0]||findValue>arr[arr.length-1]){
        return -1;
    }

    //找出預測數組中的位置
    int mid=left+(right - left) * (findValue - arr[left]) / (arr[right]-arr[left]);
    //對應的預測值
    int midValue=arr[mid];

    //若查找的值比定位的值大,則須要向右遞歸
    if(findValue>midValue){
        //若`findVale>arr[mid]`,則說明查找的數`findValue在右邊`,進行遞歸`向右查詢`
        return insertValueSearch(arr,mid+1,right,findValue);
    }else if(findValue<midValue){
        //若`findVale<arr[mid]`,則說明查找的數`findValue在左邊`,進行遞歸`向左查詢`
        return  insertValueSearch(arr,left,mid -1,findValue);
    }else{
        //若`findVale = =arr[mid]`,則說明`查找的數已找到並返回下標`
        return mid;
    }
}
int[] arr = new int[100];
for (int i = 0; i < 100; i++) {
    arr[i] = i + 1;
}
/**
 * 在元素數值均勻分佈的有序數組裏面, 用這種方法查找是很快的。
 * 特別的,對絕對均勻分佈的數組(相鄰元素差值相同), 插值查找用一次比較就能查找成功
 * 固然了,前提是數組中元素數值是均勻分佈的
 * 若是是對 1,2,40,99,1000這種分佈很不均勻的數組, 插值查找的計算會起到反效果, 就不如二分查找了
 */
int index=insertValueSearch(arr,0,arr.length-1,100);
System.out.println("查找的值對應下標是:"+index);

運行結果以下:
查找的值對應下標是:99

4、插值查找注意事項

在元素數值均勻分佈的有序數組裏面, 用這種方法查找是很快的。特別的,對絕對均勻分佈的數組(相鄰元素差值相同), 插值查找用一次比較就能查找成功:

固然了, 前提是數組中元素數值是均勻分佈的, 若是是對 1,2,40,99,1000 這種分佈很不均勻的數組, 插值查找的計算會起到反效果, 就不如二分查找了

5、算法複雜度分析

時間複雜度平均爲:O(logn)

相關文章
相關標籤/搜索