斐波那契数列

斐波那契数列,该数列公式为F(K) = F(k-1) + F(k-2),即 1、1、2、3、5、8、13、21……。F(k-1)/f(K)随着K的递增,该数越来越接近黄金分割比例,所以该方法也叫黄金分割法。

斐波那契查找算法也叫做黄金分割查找

原理

对于一个数组来说,如果数组长度为契波纳切数列中的某一个数字,那么我们就可以用黄金分割比例来分割该数组。当然,如果数组长度没有达到要求,那么我们可以尝试它扩大来满足要求,

其实,该算法的本质也还是二分法,只不过跟插入排序法一样,也是将目标的mid值改变成其它的,以至于分割的结果不一样,查找的效果也不一样。【也就是说,真正需要我们做的是找到这个mid】

那么具体是怎样分割的呢?这里的mid不再是折半或者插值得到,而是位于黄金分割点附近,即mid = low + F(k-1) -1

这里用图片直观理解一下:

对F(k-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

即:斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[ n ],将原查找表扩展为长度为F[n] (如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。

ps:二分查找, 插值查找和裴波那契查找的基础其实都是:对数组进行分割, 只是各自的标准不同: 二分是从数组的一半分, 插值是按预测的位置分, 而裴波那契是按它数列的数值分。

例子

一个例子

对于斐波那契数列:1、1、2、3、5、8、13、21、34、55、89……(也可以从0开始),前后两个数字的比值随着数列的增加,越来越接近黄金比值0.618。

比如这里的89,把它想象成整个有序表的元素个数,而89是由前面的两个斐波那契数34和55相加之后的和,也就是说把元素个数为89的有序表分成由前55个数据元素组成的前半段和由后34个数据元素组成的后半段,那么前半段元素个数和整个有序表长度的比值就接近黄金比值0.618,假如要查找的元素在前半段,那么继续按照斐波那契数列来看,55 = 34 + 21,所以继续把前半段分成前34个数据元素的前半段和后21个元素的后半段,继续查找,如此反复,直到查找成功或失败,这样就把斐波那契数列应用到查找算法中了。

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

例子二

1、目前由一个有序递增数组,要在这个数组中找元素99

2、创建一个斐波那契数列,根据:

也即是:斐波那契数列要求原始表中记录的个数为某个斐波那契数列 -1 ,也就是数组长度应该是 arr.length = Fabonacci(k) - 1.
又因为数组的长度不一定刚好是Fabonacci(k) - 1。

  • 如果大于等于,直接返回k
  • 如果斐波那契数列 - 1 小于 arr.length, 那么k++ : 也就是要查找的区间应该比当前k要大
int k = 0;
while(arr.length > Fabonacci(k) - 1){k++;
}// 当Fab(k) - 1刚好等于数组长度或者略大于数组长度时,当前的k就是我们期待的数组长度,因此跳出循环


3、如果原始表的长度就是我们期望的数组长度就什么也不干,如果原始数组中的长度小于我们期望的长度F(k), 则将原始数组的长度扩展到F(n):(如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素)。

又因为java中数组的长度是固定的,因此我们创建一个临时数组,将原始数组复制到临时数组,并补充元素

int[] temp = Arrays.copy(arr, Fabonacci(k));
for(int i = arr.length; i < temp.length; i++){temp[i] = arr[arr.length - 1];
}

3、完成后进行契波纳切数分割·,即F(k)的元素分割为前半部分F(k - 1)个元素,后半部分F(k-2)个元素

  • 没有开始之前:low = 0, high = arr.length - 1;临时数组长度为fab(k)
  • 求出mid = low + fab(k-1) -1

当目标值大于中间值时,k = k - 2;
为什么是k -= 2:

  • 全部元素 = 前面的元素 + 后面的元素
  • F[k] = F[k - 1] + F[k - 2] 【应该向右边找】
  • 因为后面我们又F[k-1] = F[k-3] + F[k - 4]
  • 即在f[k-2] 的前面进行查找 k -=2
  • 即下次循环 mid = f[k - 1 - 2] - 1
  1. 找出要查找的元素在那一部分并递归,直到找到。

代码实现

目标数组必须是有序数组。

public class TreeNode {private static int maxSize = 20;public static int[] fib() {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 a  数组* @param key 我们需要查找的关键码(值)* @return 返回对应的下标,如果没有-1*/public static int fibSearch(int[] a, int key) {int low = 0;int high = a.length - 1;int k = 0; //表示斐波那契分割数值的下标int mid = 0; //存放mid值int f[] = fib(); //获取到斐波那契数列//获取到斐波那契分割数值的下标while(high > f[k] - 1) {k++;}//因为 f[k] 值 可能大于 a 的 长度,因此我们需要使用Arrays类,构造一个新的数组,并指向temp[]//不足的部分会使用0填充int[] temp = Arrays.copyOf(a, f[k]);//实际上需求使用a数组最后的数填充 temp//举例://temp = {1,8, 10, 89, 1000, 1234, 0, 0}  => {1,8, 10, 89, 1000, 1234, 1234, 1234,}for(int i = high + 1; i < temp.length; i++) {temp[i] = a[high];}// 使用while来循环处理,找到我们的数 keywhile (low <= high) { // 只要这个条件满足,就可以找mid = low + f[k - 1] - 1;if(key < temp[mid]) { //我们应该继续向数组的前面查找(左边)high = mid - 1;//为甚是 k--//说明//1. 全部元素 = 前面的元素 + 后边元素//2. f[k] = f[k-1] + f[k-2]//因为 前面有 f[k-1]个元素,所以可以继续拆分 f[k-1] = f[k-2] + f[k-3]//即 在 f[k-1] 的前面继续查找 k--//即下次循环 mid = f[k-1-1]-1k--;} else if ( key > temp[mid]) { // 我们应该继续向数组的后面查找(右边)low = mid + 1;//为什么是k -=2//说明//1. 全部元素 = 前面的元素 + 后边元素//2. f[k] = f[k-1] + f[k-2]//3. 因为后面我们有f[k-2] 所以可以继续拆分 f[k-1] = f[k-3] + f[k-4]//4. 即在f[k-2] 的前面进行查找 k -=2//5. 即下次循环 mid = f[k - 1 - 2] - 1k -= 2;} else { //找到//需要确定,返回的是哪个下标if(mid <= high) {return mid;} else {return high;}}}return -1;}public static void main(String[] args) {int arr[] ={1,2, 3, 4, 5, 99 , 100};int i =  fibSearch(arr, 99);if (i == -1){System.out.println("找不到");}else{System.out.println("索引" +i+ "值" + arr[i]);}}
}

为什么不直接用(hi-lo)*0.618来寻找分割点

为什么不直接用(hi-lo) * 0.618来寻找分割点?这个问题我个人的看法是乘法的开销较大,而且对于查找效果的提高有限。斐波那契数前后项之比 fib(n) / fib(n - 1) 也只是在n比较大的时候才接近黄金比例1.618…,而且区间的长度不一定为某个斐波那契数减一(也有可能查找的目标是最后一个数嘛),所以斐波那契查找的意义应该是在效果与开销之间找到一个平衡,使效率尽可能的最大化

斐波那契查找的时间复杂度还是O(log2n):斐波那契查找,就平均性能而言,要优于二分查找,但是如果是最坏的情况,比如key=0,那么始终在左侧长半区在查找,查找的效率要低于折半查找。

算法与数据结构学习(31)-斐波那契(黄金分割法)查找算法

斐波那契查找算法
参考

算法:斐波那契(黄金分割法)查找算法相关推荐

  1. 我所知道查找算法之斐波拉契(黄金分割法)查找

    作者前言 大家好,我是阿濠,今篇内容跟大家分享的是查找算法之斐波那契(黄金分割法)查找,很高兴分享到segmentfault与大家一起学习交流,初次见面请大家多多关照,一起学习进步. 一.斐波那契数列 ...

  2. 数据结构与算法-查找算法(二分查找,插值查找,斐波那契(黄金分割法)查找)

    查找算法 以下三种算法的基本思想相同,都是利用递归来寻找 二分查找 思路分析 1.首先确定该数组的中间下标,min = (left + right) / 2 2.然后让需要查找的的数findVal和a ...

  3. JavaScript实现闭式函数计算特定位置的斐波那契数fibonacciNthClosedForm算法(附完整源码)

    JavaScript实现闭式函数计算特定位置的斐波那契数fibonacciNthClosedForm算法(附完整源码) fibonacciNthClosedForm.js完整源代码 fibonacci ...

  4. JavaScript实现动态规划方法计算特定位置的斐波那契数fibonacciNth算法(附完整源码)

    JavaScript实现动态规划方法计算特定位置的斐波那契数fibonacciNth算法(附完整源码) fibonacciNth.js完整源代码 fibonacciNth.js完整源代码 export ...

  5. JavaScript实现以数组形式返回斐波那契数列fibonacci算法(附完整源码)

    JavaScript实现以数组形式返回斐波那契数列fibonacci算法(附完整源码) fibonacci.js完整源代码 fibonacci.js完整源代码 export default funct ...

  6. C语言DP备忘计算指数N的斐波那契级数的算法(附完整源码)

    C语言DP备忘计算指数N的斐波那契级数的算法 C语言DP备忘计算指数N的斐波那契级数的算法完整源码(定义,实现,main函数测试) C语言DP备忘计算指数N的斐波那契级数的算法完整源码(定义,实现,m ...

  7. Java数据结构与算法---斐波那契数列Fibonacci

    Java数据结构与算法-斐波那契数列Fibonacci 原理都很简单,直接上代码: package cn.m_fibonacci;public class Fibonacci {public stat ...

  8. 斐波那契数列系列算法最优复杂度-------O(logN)

    斐波那契数列系列算法最优复杂度--时间复杂度优化到O(LogN) 对于菲薄那契系列问题的探讨很多,下面就以两个例子来分析: 案例 一: 在迷迷糊糊的大草原上,小红捡到了n根木棍,第i根木棍的长度为i, ...

  9. 数据结构与算法 | 斐波那契查找

    要想能够理解这一算法,需要先了解 1.二分查找 https://blog.csdn.net/qq_35423154/article/details/101383518 2.斐波那契数 https:// ...

  10. 数据结构三大查找算法(二分查找、插值查找、斐波那契数列查找)C语言实现

    文章目录 查找 二分查找(折半查找) 插值查找 斐波拉契查找 总结: 查找 查找是在大量的信息里面寻找一个特定的信息元素 (1)静态查找和动态查找: 静态或者动态都是针对查找表而言的.动态表指查找表中 ...

最新文章

  1. 以太坊,EOS和其他DApps的总数达到2,432,但没有大规模采用
  2. python线性加权回归_python深度学习-tensorflow实现一个线性回归的案例
  3. 【分析】2014移动互联网数据报告(终极版必收!)
  4. JAVA继承类phone_JAVA(9)继承与多态
  5. 【bzoj3994】[SDOI2015]约数个数和 莫比乌斯反演
  6. 飞行摇杆设置_HORI皇牌空战7最新飞行摇杆抢先开箱 设计出色布局合理
  7. QT5主界面“关闭窗口”按钮设置弹出提示询问信息
  8. 低版本系统兼容的ActionBar(六)用Fragment+ViewPager+Tab实现快速导航
  9. arm 饱和指令_ARM内核全解析,从ARM7,ARM9到CortexA7,A8,A9,A12,A15到CortexA53,A57
  10. 有关Wiki的三个应用
  11. 电驴让分享继续 服务器不稳定,为什么越来越多的人不再使用eD2k了?回顾电驴的兴与衰...
  12. 用latex生成pdf文件后,文本复制粘贴显示乱码
  13. 计算机网络 可靠数据传输原理——从rdt协议到GBN到SR
  14. Android-工作遭遇-URLConnection原生请求http和https忽略证书
  15. 计算机未来新CPU,桌面CPU性能排行 CPU天梯图2017年11月最新版 (全文)
  16. Window 10 电源高性能模式设置
  17. HDOJ 1197 Specialized Four-Digit Numbers 特别的四位数
  18. 【Linux】Linux安装
  19. x58和x79服务器性能,Intel X58接班人:X79官方规格全曝光
  20. (史上最详细)C++实战-基于STL 演讲比赛流程管理系统

热门文章

  1. MedSegDiff:基于 Diffusion Probabilistic Model 的医学图像分割
  2. jQuery AJAX 方法 success()后台传来的4种数据
  3. 我的世界怎么用计算机,我的世界计算器怎么用 全计算器使用说明
  4. 天融信堡垒机怎么结合国密OTP动态令牌实现双因子身份认证?
  5. 安卓app设计规范整理和Android APP设计
  6. Java Swing对话框
  7. 上天赐予的财富和才能要回馈社会
  8. 听女友讲女厕所发生的故事,你们女人真的太难了吧!
  9. 论文《Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts》
  10. 详解K-Means算法