2020-08-27

斐波那契查找法(黄金分割法):

黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。其比值是一个无理数,用分数表示为(√5-1)/2,取其前三位数字的近似值是0.618。

斐波那契查找法与二分查找法、插值查找法相似,只是mid不再取中间值,而是取黄金分割点附近,即mid = low + F[k-1] -1。F代表着斐波那契数列。

***斐波那契实现原理:

其实该查找法就是借助斐波拉契数列,首先判断自身数组长度是否与斐波那契数列里面其中的值相等,如果不相等,就一直查找到斐波那契里面的值。此时取到的f[k] = f[k-1] + f[k-2],f[k-1]其实就是我们的mid。
然后也像二分查找法一样,向左向右递归查找,直至找到为止。***

举例说明:

(1)现有斐波那契数列::1、1、2、3、5、8、… 数组arr={1,2,3,4,5,6,7}
(2)arr.length不等于斐波那契数列其中的值,但接近8,所以f[k]=8,k=5
(3)创建一个临时数组temp[k],把arr的值赋给temp,此时arr.length不等于temp.length,
多出来的部分系统会自动生成为0,然后把arr[high]的值添加到temp数组末尾。
(4)求mid的值,由于f[k] = f[k-1] + f[k-2],所以f[5] = f[4] + f[3],则mid = 0 + f[4] = 5
(5)找到mid值后进行左右递归查找,直至找到为止。

实现代码:

package com.java;

import java.util.Arrays;

public class FibonacciSearch {
    //定义一个常量,接收fib数列最大值
    public static int maxSize = 20;
    public static void main(String[] args) {
        int[] arr = {1,23,65,79,89,121,214};
        System.out.println(fibonacciSearch(arr, 79));
    }

    //定义创建斐波那契数列方法
    public static int[] fib()
    {
        int[] f = new int[maxSize];
        f[0] = f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i-1] + f[i-2];
        }
        return f;
    }
    /*定义斐波那契查找法

    *需要接收数组(arr),以及需要查找的值(findVal)
    */
    public static int fibonacciSearch(int[] arr,int findVal)
    {
        int low = 0;//定义数组左索引
        int high = arr.length - 1;//定义数组右索引
        int mid = 0;//存放mid值
        int k = 0;//存放斐波那契分割数值的下标
        int[] f = fib();//获取斐波那契数列
        //寻找数组长度值与斐波那契数列相等的值,
        // 没找到之前把数组最后一项增添到新数组中.
        //此时数组长度与斐波那契数列相等的值就为中间值!
        while (high > f[k] - 1)
            k++;//此时k的值为mid索引
        //创建临时数组temp,此时f[k]的值为temp数组长度
        int[] temp = Arrays.copyOf(arr,f[k]);
        //把temp数组后面的0用arr[high]填充
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = arr[high];
        }
        //寻找findVal
        while (low <= high)//成立条件
        {
            mid = low + f[k-1] - 1;
            if (findVal < temp[mid])//此时向左递归查找
            {
                high = mid - 1;
                k--;//f[k-1] = f[k-2] + f[k-3]由于要在f[k-1]前面继续查找,所以k--
                //即下次循环mid = low + f[k-1-1] -1
            }else if (findVal > temp[mid])//此时向右递归
            {
                low = mid + 1;
                k -= 2;//f[k-2] = f[k-3] + f[k-4]// 由于要在f[k-2]后面继续查找,所以k-=2
                //即下次循环mid = low + f[k-1-2] -1
            }else {//此时意味着找到了
                if (mid <= high)//确定返回值
                    return mid;
                else
                    return high;
            }
        }
        return -1;
    }

}

猜你喜欢

转载自blog.csdn.net/zzFZJ_/article/details/108256917