java數據結構之插值查找和斐波那契查找

插值查找:

二分查找在確定中間值的位置的時候,使用的公式爲:
    mid = (right + left) / 2
    此公式可以轉換爲:mid = left + (right - left) / 2
    上面的公式中 1/2 我們可以進行優化:
    設要查找的值爲 targetVal
    (targetVal - a[left]) / (a[right] - a[left]) * (right - left)
    此公shi能夠比較快速的定位到 targetVal傾向於偏到哪一個方向
    因此有 mid = left + (right - left) * (targetVal - a[left]) / (a[right] - a[left])
    優於 mid = left + (right - left) / 2,同樣插值查找也需要數組是有序的,在a中的值分佈不均勻,跳躍性很大的
    情況下,插值查找不一定比二分查找好

 

代碼:

public class InsertValueSearch {
    public static void main(String[] args) {
        int len = 100;
        int[] a = new int[len];
        for ( int i = 0; i < len; i++) {
            a[i] = i;
        }
        int findVal = 45;
        int pos = insertSearch(a, 0, a.length-1, findVal);
        System.out.printf("要查找的值爲:%d, pos:%d\n", findVal, pos);
    }

    //找到返回對應的下標,找不到返回-1
    public static int insertSearch(int a[], int left, int right, int findVal) {
        System.out.println("Hello~~");
       //插值查找 findVal < a[left] || a[right] < findVal 必須有
        if (left > right || findVal < a[left] || a[right] < findVal) {

            return -1;
        }
        int mid = left +  (right - left) * (findVal - a[left]) / (a[right] - a[left]);
        int midVal = a[mid];

        if (findVal > midVal) {
            return insertSearch(a, mid+1, right, findVal);
        } else if (findVal < midVal) {
            return insertSearch(a, left, mid-1, findVal);
        } else {
            return mid;
        }

    }

}

斐波那契查找

   0.618讓人看了很舒服
   在二分查找確定 1/2的時候,我們可以確定0.618
   斐波那契數前一個數比上後一個數的比例接近於0.618

代碼:

public class FibonacciSearch {
    public static void main(String[] args) {
        int len = 100;
        int[] a = new int[len];
        for ( int i = 0; i < len; i++) {
            a[i] = i;
        }
        int[] a1 = {1, 8, 10,89,1000,1234};
        int findVal = 45;
        int i = fibonacciSearch(a1, findVal);

    }

    public static int fibonacciSearch(int a[], int findVal) {
        int low = 0;
        int high = a.length - 1;
        int k = 0;
        int mid = 0; //
        int f[] = fib(20);

        //獲取到斐波那契數值的下標
        while (high > f[k] - 1) {
            k++;
        }
        //因爲f[k] 值可能大於數組的長度,因此使用Arrays類構造一個新的數組,並指向a[]
        //不足的部分使用0填充
        int[] tmp = Arrays.copyOf(a, f[k]);
        //需要使用a數組最後的數填充tmp
        for (int i =  high+1; i < tmp.length; i++) {
            tmp[i] = a[high];
        }

        //循環查找,直到找到目標數
        while (low <= high) {
            mid = low + f[k-1] -1;
            if (findVal < tmp[mid]) { //向數組前面查找
                high = mid-1;
                k--; //全部元素 = 前面的元素 + 後面的元素。 f[k] = f[k-1] + f[k-2]
                //前面有f[k-1]個元素,所以可以繼續拆分 f[k-1] = f[k-2] + f[k-3],即在f[k-1]的前面繼續查找
            } else if (findVal > tmp[mid]) { //想數組後面查找
                low = mid+1;
                k -= 2; //全部元素 = 前面元素 + 後面元素
                //f[k] = f[k-1]+ f[k-2], 因爲f
            } else {
                //需要確定返回的是哪一個座標
                if (mid <= high) {
                    return mid;
                } else {
                    return high;
                }


            }
        }

        return  -1;
    }

    //非遞歸方法獲取斐波那契數列
    public static int[] fib(int maxSize) {
        int[] f = new int[maxSize];
        if (maxSize < 2) {
            f = new int[2];
        }

        f[0]= 1;
        f[1] = 1;
        for (int i = 2; i < f.length; i++) {
            f[i] = f[i-1]+f[i-2];
        }

        return f;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章