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

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

斐波那契(黄金分割法)原理:**斐波那契查找**原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值位于黄金割点附近,即==**mid=low+F(k-1)-1**==
(F代表斐波那契数列),如下图所示

对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=low+F(k-1)-1

2)类似的,每一子段也可以用相同的方式分割

3)但顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。

当我们在mid左边进行查找时:

这时f[k-1]就相当于F[k]了
所以此时的斐波那契公式就变成了 F[k-1] = F[(K-1)-1]+F[(K-1)-2]即 F[k-1] = F[K-2]+F[K-3]

如下图:如果向右边查找也是也一样的拆分道理

代码:

package com.lzh.search;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 斐波那契查找算法
 * 也是要求数组是有序的
 */
public class FibonacciSearch {
    //定义一个斐波那契数列的长度
    private static int maxSize = 20;
    public static void main(String[] args) {
        int[] arr = {1,8, 10, 89, 1000, 1234,1235,1236};
        int index = fibSearch(arr,1235);
        System.out.println("要查找的数的下标为:"+index);


    }
    //用非递归的方法得到一个斐波那契数列
    public static int[] fib(){
        //创建一个用来存放斐波那契数列的数组
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        //斐波那契公式
        // f[k] = f[k-1] + f[k-2];
        for (int i = 2;i < maxSize; i++){
            f[i] = f[i-1] + f[i-2];
        }
        return f;
    }

    /**
     * 斐波那契查找
     * @param arr 要查找的数组
     * @param key 要查找的数值
     * @return 返回要查找的数的下标
     */
    public static int fibSearch(int[] arr,int key){
        //定义各个元素
        int low = 0;//数组最左边的索引
        int high = arr.length - 1;
        int mid = 0;//黄金分割点
        int k = 0;//斐波那契数列的下标
        int f[] = fib();//得到斐波那契数列
        //会有这么一种情况,当要查找的数组的长度不够时,是无法用斐波那契进行查找的,所以我们这里判断数组的长度是否小于斐波那契数列中的元素
        //只有当f[k]-1的值大于或等于数组最大下标的时候,我们得到一个斐波那契数列中的值,然后对比数组的长度,如果数组的长度比这个斐波那契数列中的值小,我们就要对数组进行扩容。
        //即得到k的值
        while(arr.length > f[k] - 1){
            k++;
        }
        //对arr数组进行扩容
        //f[k] 为斐波那契数列中的值,后面扩充的位置用0补充
        int[] temp = Arrays.copyOf(arr,f[k]);
        //但实际上我们要用原数组的最后一个数,进行填充
        //int i = high + 1 意思是从原数组最后一位的下一位开始填充
        for (int i = high+1; i < temp.length;i++){
            temp[i] = arr[high];//让扩容的位置用数组最后一位数值填充
        }
        //开始使用斐波那契进行查找数值
        while(low <= high){//左边的索引小于右边的索引就一直循环
            mid = low + f[k-1] -1;//用斐波那契数列中的值+low-1得到temp数组的黄金分割点
            if (key < temp[mid]){ //要查找的值小于temp[mid]的值的话就往左边进行查找
                high = mid - 1;//让mid左边的值当成最右边的索引
                /**
                 * 斐波那契数列公式 F[K] = F[K - 1]  +F[K - 2]
                 * 这里的k--是因为我们向左进行查找了,这时f[k-1]就相当于F[k]了
                 * 所以此时的斐波那契公式就变成了 F[k-1] = F[(K-1)-1]+F[(K-1)-2]即 F[k-1] = F[K-2]+F[K-3]
                 * 如果下一轮还是往左进行查找,就继续这样拆分
                 */
                k--;
            }else if (key > temp[mid]){ //要查找的值小于temp[mid]的值的话就往右边进行查找
                low = mid + 1;//让mid右边的第一个值当成最左边的索引
                /**
                 * 斐波那契数列公式 F[K] = F[K - 1]  +F[K - 2]
                 * 这里的k -= 2是因为我们向右进行查找了,这时f[k-2]就相当于F[k]了
                 * 所以此时的斐波那契公式就变成了 F[k-2] = F[(K-2)-1]+F[(K-2)-2]即 F[k-2] = F[K-3]+F[K-4]
                 * 如果下一轮还是往右进行查找,就继续这样拆分
                 */
                k -= 2;
            }else{
                //如果都不满足,就代表找到了这个数的下标
                if (mid <= high){//如果mid<=high就代表我们的mid是要查找的下标,所以把mid返回出去
                    return mid;
                }else{
                    return high;//否则的话high是我们要查找的下标
                }
            }
        }
        //如果循环查找之后没找到,就代表这个数组中没有我们要查找的数,所以我们这里返回-1
        return -1;
    }



}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值