斐波那契查找

/**
 * 斐波那契查找,就是利用斐波那契数来构造数组,寻找黄金分割点的数字和待查找数字比较(后面的操作类似二分查找)
 *
 * 斐波那契数组的特点:
 * 1.前两个数外,后面的数都位前两位数的和
 * 2.前一个数与后一个数的比例接近0.618,也就是黄金分割率
 *
 * 1.构造长度为斐波那契数的数组
 * 1.1
 * 二十位斐波那契数组:F[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
 * 如果原数组长度为10,那么构造后符合条件的数组长度最少为13.
 * 1.2
 * 新构造的数组超过原数组的位数默认为0,需要全部补为原数组的最后一个数
 *
 * 2计算mid值,按照斐波那契数字的规律
 * 新数组newarr可以分为F[k-1]和F[k-2]两部分,k为新数组长度,F为斐波那契数组,F[k-1]/F[k-2]接近0.618
 * 新数组的索引范围为0--(k-1) 头索引为0 ,尾索引为newarr.length-1
 * mid=zuo + F[k-1]-1
 *
 *  对 F(k-1)-1 的理解:
 * 1) 由斐波那契数列 F[k]=F[k-1]+F[k-2] 的性质,可以得到 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1 。该式说明:
 * 只要顺序表的长度为 F[k]-1,则可以将该表分成长度为 F[k-1]-1 和 F[k-2]-1 的两段,即如上图所示。从而中间位置为 mid=zuo+F(k-1)-1
 * 说明:数组内每个元素都占一个索引
 *
 * 3.比较newarr[mid]与待查找值的大小
 * 定义两个指针l和r,初始值为newarr数组的最大最小索引,作为循环退出条件
 * 如果l>r,说明把数组按各个元素切分都没有找到,就表示值不存在,退出循环
 * 循环:
 * 如果待查找值比newarr[mid]大,表示待查数在右边
 * l=mid+1;
 * 此时k的值-1,每次拆分后数组的长度对应斐波那契数组元素,其实这里还与计算公式有关
 * 例如13 分为5 ,8
 *     8  分为5 ,3
 * 如果待查找值比newarr[mid]小,表示待查数在左边
 *  r=mid-1
 *  此时k的值-2,每次拆分后数组的长度对应斐波那契数组元素,
 *  例如13 分为5 ,8
 *  *   5 分为3 ,2
 *
 *4.返回值
 *
 * 假如mid值落在了原来的数组扩容后的索引上
 * 就要返回arr.length-1 因为扩容后多余的位置都是用arr[arr.length-1]填充的
 * 假如mid值没有超过arr.length-1,表示mid值没有落在了原来的数组扩容后的索引上
 * 就直接返回mid,此时mid索引的数字就是要查找的数
 *
 */


/*
关键点:1.构造斐波那契数列
       2.mid值的计算
       3.递归(循环)结束条件,k值变化情况
       4.返回值是否落入扩容后多余索引上
 */

public class 斐波那契查找 {

    public static  final int max=20;

    public static void main(String[] args) {

        int[] arr={4,6,7,9,13,16,21,30,42,76};

        System.out.println(FibonacciSearch(arr, 0, arr.length - 1,17));


        System.out.println(Arrays.toString(fei()));
    }



    public static int[] fei(){
        int[] Farr=new int[max];
        Farr[0]=Farr[1]=1;

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

    public static int FibonacciSearch(int[] arr,int left ,int right,int element){

        int zuo=left;
        int you=right;


        int k=0;
        int mid;
        int[] farr=fei();
        int[] newArr=null;

        while (arr.length>farr[k]){
            k++;
        }

        if (farr[k]>=arr.length){
        newArr = Arrays.copyOf(arr, farr[k]);

         //补齐多余位置的数
         for (int i=0;i<farr[k]-arr.length;i++){
             newArr[arr.length+i]=arr[arr.length-1];
         }
        }

        //此时长度为斐波那契数的数组终于构造完成,可以开始计算mid了

        while(zuo<=you){
            mid=zuo+farr[k-1]-1;
           //向右寻找

            if (element>newArr[mid]){
                zuo=mid+1;

                k-=2;

            }
            //向左寻找
           else if (element<newArr[mid]){
                you=mid-1;

                k-=1;
            }else {
               //返回待查找数字的索引
               if (mid>right){
                   return arr.length-1;
               }else  {
                   return mid;
               }
            }
        }

        return -1;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
斐波那契查找算法是一种基于二分查找算法查找算法,它利用了斐波那契数列的特性来确定查找的位置。下面是斐波那契查找算法的设计步骤: 1. 首先,需要确定斐波那契数列的长度,使得它大于等于待查找数组的长度。假设斐波那契数列的长度为n,那么有:F(n) = F(n-1) + F(n-2),其中F(0) = 0,F(1) = 1。 2. 然后,需要将待查找数组扩展到长度为n,扩展的部分用原数组的最后一个元素填充。 3. 接着,需要定义两个指针:low和high。初始时,low指向待查找数组的第一个元素,high指向斐波那契数列中第一个大于等于n的元素的下标减1。 4. 然后,需要计算mid的值,mid的值为low加上斐波那契数列中第k-1个元素的值,其中k为满足F(k)-1 >= n的最小值。 5. 然后,比较待查找数组中第mid个元素和要查找的元素的大小。如果待查找数组中第mid个元素小于要查找的元素,则将low指向mid+1;如果待查找数组中第mid个元素大于要查找的元素,则将high指向mid-1;否则,找到了要查找的元素,返回mid。 6. 重复步骤4和步骤5,直到low大于high为止。 下面是一个Python实现的斐波那契查找算法的例子: ```python def fibonacci_search(arr, x): n = len(arr) fib_k2 = 0 # F(k-2) fib_k1 = 1 # F(k-1) fib_k = fib_k1 + fib_k2 # F(k) while fib_k < n: fib_k2 = fib_k1 fib_k1 = fib_k fib_k = fib_k1 + fib_k2 offset = -1 while fib_k > 1: i = min(offset+fib_k2, n-1) if arr[i] < x: fib_k = fib_k1 fib_k1 = fib_k2 fib_k2 = fib_k - fib_k1 offset = i elif arr[i] > x: fib_k = fib_k2 fib_k1 = fib_k1 - fib_k2 fib_k2 = fib_k - fib_k1 else: return i if fib_k1 and arr[offset+1] == x: return offset+1 return -1 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值