zoukankan      html  css  js  c++  java
  • 24、查找算法-斐波那契查找

    来源:https://www.bilibili.com/video/BV1B4411H76f?p=77

    一、思路

    斐波那契查找:也可以说是黄金分割法查找,斐波那契序列{1,1,2,3,5,8,13...},相邻两个数的比值无限接近于黄金分割值(0.618)。这里还是对中间下标mid进行修改。

    斐波那契满足的性质是这样的: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,剩下那个1就是一个中间值。现在,长度划分好了。有两个问题:原始长度不满足F(k)-1怎么办?mid下标怎么计算?

    原始长度可以通过扩充的形式来增长,增长的部分用原始数组的最后一个数填补;

    mid=low+F(k-1)-1,即左边是较长的一部分,右边较短。

    二、实现

     1 //斐波那契查找
     2 public class FibonacciSearch {
     3     //给定一个斐波那契数组的最大长度
     4     public static int MAXSIZE = 20;
     5 
     6     public static void main(String[] args) {
     7         int[] arr = {1,8,10,89,1000,1234};
     8         System.out.println(Arrays.toString(arr));
     9 
    10         int a = fibSearch(arr,89);
    11         System.out.println(a);
    12     }
    13 
    14     //给定斐波那契的所有情况
    15     public static int[] fib(){
    16         int[] f = new int[MAXSIZE];
    17         f[0] = 1;
    18         f[1] = 1;
    19         for (int i = 2; i < MAXSIZE; i++) {
    20             f[i] = f[i-1]+f[i-2];
    21         }
    22         return f;
    23     }
    24 
    25     public static int fibSearch(int[] arr,int finalVal){
    26         int left = 0;
    27         int right = arr.length - 1;
    28         //长度补齐
    29         int[] fib = fib();
    30         int k = 0;//找长度
    31         while(right > fib[k] - 1){
    32             k++;
    33         }
    34         int[] temp = Arrays.copyOf(arr,fib[k]);//补齐
    35         for (int i = right + 1; i < temp.length; i++) {
    36             temp[i] = arr[right];
    37         }
    38 
    39         int mid = 0;
    40         while (left <= right){
    41             mid = left + fib[k-1] - 1;
    42             if(finalVal < temp[mid]){
    43                 //向左找
    44                 right = mid - 1;
    45                 //按照mid的计算方式,左边是较长的序列,其长度对应的是k-1这个下标的前一个k-1-1
    46                 k -= 1;
    47             }else if (finalVal > temp[mid]){
    48                 //向右找
    49                 left = mid + 1;
    50                 //按照mid的计算方式,右边是较短的序列,其长度对应的是k-1这个下标的前两个k-1-2
    51                 k -= 2;
    52             }else {
    53                 //因为之前扩容过,得看找到的这个mid在不在扩容的范围里面(返回的是下标,在扩容的里面就是数组最后一个)
    54                 if(mid <= right){
    55                     //不属于扩容的范围
    56                     return mid;
    57                 }else {
    58                     return right;
    59                 }
    60             }
    61         }
    62         return -1;
    63     }
    64 }

    这里用递归好像反而不好整了,需要单独将补齐的工作分开,输入进去的应该是补齐后的数组。输出的时候也要单独判断在不在扩充区。

  • 相关阅读:
    [GEiv]第七章:着色器 高效GPU渲染方案
    Cocos2d-x 脚本语言Lua介绍
    TestNg依靠先进的采用强制的依赖,并依赖序列的------TestNg依赖于特定的解释(两)
    uboot通过使用U磁盘引导内核RT5350成功
    linux下一个rsync工具和配置
    STM32 模拟I2C (STM32F051)
    Something write in FSE 2014
    ESB (Enterprise Service Bus) 入门
    Spring框架:Spring安全
    “TNS-03505:无法解析名称”问题解决一例
  • 原文地址:https://www.cnblogs.com/zhao-xin/p/13168448.html
Copyright © 2011-2022 走看看