斐波那契查找算法詳解


斐波那契查找算法詳解

說明

  1. 斐波那契查找算法核心思想類似於二分查找和插值查找,區別在於對標志值,即 mid 的設計算法不一樣,二分查找直接重用中間值作為標桿,插值查找使用自適應確定mid,而斐波那契查找算法則使用黃金分割,使得mid總是處於查找數列的黃金分割點位置
  2. 因為斐波那契數列越到后邊,相鄰兩數的比值越發接近0.618,也就是黃金分割比,因為可以巧妙的使用斐波那契數列尋找數組中的黃金分割點,即mid對應的下標
  3. 因此需要先構建一個斐波那契數列,可以使用遞歸的方法或者非遞歸的方式
  4. 使用斐波那契數列尋找數組的黃金分割點公式為: mid = low + f (k - 1) - 1,k為當前斐波那契數對應的索引
  5. 使用斐波那契數列查找,需要先將當前數組的長度構建為第一個比數組長度大的斐波那契數,這個數對應的索引就是 k ,可以使用循環的方法
  6. 將構建的新數組后邊補零的位置替換為數組中的最后一個位置,即最大值
  7. 准備工作准備好后,就可以計算當前數組的黃金分割值,然后獲取到當前黃金分割值對應的元素
  8. 將這個元素和要查找的元素進行比較,然后重置左右指針和重置后數組對應的黃金分割點
  9. 當查找完所有的元素后,如果沒有找到,則返回 - 1
  10. 注意斐波那契數列的特性 即 當索引 > 2時,當前位置元素 = 前兩個位置元素之和,而前兩個位置元素之比剛好是滿足黃金分割,正是基於這樣的特性,才有公式 mid = low + f (k - 1) - 1
  11. 斐波那契查找算法不易理解,須慢慢體會
  12. 源碼及詳解見下

源碼及分析

//斐波那契數列的最大長度
    public static int maxSize = 20;

    public static void main(String[] args) {
        int[] arr = {1, 23, 45, 66, 67, 88, 90, 100};
        int index = fisSearch(arr, 88);
        System.out.println("index = " +index);

    }

    //構建斐波那契數列
    public static int[] fis() {
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < f.length; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }
    /**
     * 斐波那契查找算法實現
     *
     * @param arr 要查找的原始數組
     * @param key 要查找的值
     * @return 查找的結果
     */
    public static int fisSearch(int[] arr, int key) {
        //數組左側索引
        int low = 0;
        //數組右側索引
        int high = arr.length - 1;
        //比右側索引大的第一個斐波那契數對應的索引
        int k = 0;
        //黃金分割點
        int mid = 0;
        //斐波那契數列
        int[] f = fis();
        //由數組最大值計算k
        while (high > f[k] - 1) {
            k++;
        }

        //因為f[k]的值可能大於數組的長度,因此需要給原數組擴容到長度 == f(k)
        int[] tmp = Arrays.copyOf(arr, f[k]);
        //調用copyOf方法后在擴容部分全部補了0,實際上需要補數組的最后一位
        for (int i = high + 1; i < tmp.length; i++) {
            tmp[i] = arr[high];
        }
        //使用while循環來查找需要找的數
        while (low <= high) {
            //先計算黃金分割點
            mid = low + f[k - 1] - 1;
            //判斷黃金分割點的元素和要查找的元素的關系
            //如果要查找的值在mid左邊,重置high和k
            if (tmp[mid] > key){
                high = mid - 1;
                k--;
                //如果要查找的值在mid右邊
            }else if (tmp[mid] < key){
                low = mid + 1;
                k -= 2;
                //否則找到該元素
            }else {
                if (mid <= high){
                    return mid;
                }else {
                    return high;
                }
            }
        }
        //如果循環結束后還沒有找到,說明沒有
        return -1;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM