• 查找算法之斐波那契查找


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

    斐波那契算法基本介绍:

    1.黄金分割点是把一条线段分割为两部分,是其中一部分与全长之比等于另一部分与这部分之比,取其前三位数的近似值为0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割

    2.斐波那契数列{1,1,2,3,5,8,13,21,34,55}发现斐波那契数列的相邻两个数的比例,无限接近黄金分格值0.618

    3.斐波那契工作原理:斐波那契查找与二分查找和插入查找原理非常相似,仅仅改变了中间节点(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即可

    代码:

    package com.gcy.searcch;

    import java.util.Arrays;

    /**
    * 斐波那契查找算法
    * @author Administrator
    *
    */
    public class FeibonaqiSearch {
    public static int maxSize=20;
    public static void main(String[] args) {
    int[] arr= {1,8,10,89,1000,1234};
    System.out.println("所要查找的数据的下标值index="+feiSearch(arr,1234));
    }
    /**
    * 得到一个斐波那契数列
    * 使用非递归方式
    * @return
    */
    public static int[] fei() {
    int [] f=new int[maxSize];
    f[0]=1;
    f[1]=1;
    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 feiSearch(int[] arr,int key) {
    int low=0;
    int high=arr.length-1;
    int k=0;//表示斐波那契数分割数的下标值
    int mid=0;
    int[] f=fei();//调用斐波那契数列
    //获取斐波那契分割数值的下标
    while(high>(f[k]-1)) {
    k++;
    }
    //因为f[k]值可能大于a的长度,因此需要使用Arrays工具类,构造一个新法数组,并指向temp[],不足的部分会使用0补齐
    int[] temp=Arrays.copyOf(arr, f[k]);
    //实际需要使用arr数组的最后一个数来填充不足的部分
    for(int i=high+1;i<temp.length;i++) {
    temp[i]=arr[high];
    }
    //使用while循环处理,找到key值
    while(low<=high) {
    mid=low+f[k-1]-1;
    if(key<temp[mid]) {//向数组的前面部分进行查找
    high=mid-1;
    /*
    * 对k--进行理解
    * 1.全部元素=前面的元素+后面的元素
    * 2.f[k]=k[k-1]+f[k-2]
    * 因为前面有k-1个元素没所以可以继续分为f[k-1]=f[k-2]+f[k-3]
    * 即在f[k-1]的前面继续查找k--
    * 即下次循环,mid=f[k-1-1]-1
    */
    k--;
    }else if(key>temp[mid]) {//向数组的后面的部分进行查找
    low=mid+1;
    /**
    * 对k-=2理解
    * 1.全部元素=前面的元素+后面的元素
    * 2.f[k]=k[k-1]+f[k-2]
    * 3.因为后面有k-2个元素,所以可以继续拆分f[k-2]=f[k-3]+f[k-4]
    * 4.即在f[k-2]前面进行查找k-=2
    * 5.即在下次循环mid=[k-1-2]-1
    */
    k-=2;

    }else {//找到了
    //需要确定返回的是哪个下标
    if(mid<=high) {
    return mid;
    }else {
    return high;
    }
    }
    }
    return -1;
    }

    }

    结果截图:

  • 相关阅读:
    npm WARN saveError ENOENT: no such file or directory的解决方法
    简单的webpack打包案例
    JS中用encodeURIComponent编码,后台JAVA解码
    说 Redis
    let the cat out of the bag
    简述C# volatile 关键字
    螃蟹怎么分公母?是用冷水上锅还是热水蒸呢?
    Mysql截取字符串 更新字段的部分内容
    Ajax 获取数据attr后获取不到
    如何限制域名访问?白名单机制
  • 原文地址:https://www.cnblogs.com/juddy/p/13783155.html
Copyright © 2020-2023  润新知