[JDK17]斐波那契查找算法的实现原理、公式由来以及代码的实现(代码详解)

2024-03-26 04:50

本文主要是介绍[JDK17]斐波那契查找算法的实现原理、公式由来以及代码的实现(代码详解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

JDK17完整代码实现:

package SearchAlgorithm.FibonaciiSearch;import java.util.Arrays;public class FibonaciiSearch {public static void main(String[] args) {int[] arr = {1,8,10,89,1000,1200};int targetIndex = fibonaciiSearch(arr,1200);System.out.println(targetIndex);}//斐波那契数列private static int[] fibonaciiList = getFibonaciiList(20);/*** 斐波那契查找算法(非递归算法)* 思路是利用数组长度,计算数组中的黄金分割点mid* 首先要清楚我们要把斐波那契数列中的每一个值当成数组的长度去看待,那么该数组长度的黄金分割点就是斐波那契数列的前一个值* @param arr* @param target* @return*/public static int fibonaciiSearch(int[] arr, int target) {//举例arr数组{1,8,10,89,1000,1200}int left = 0;int right = arr.length - 1;//k是指向斐波那契数列的索引,k所对应的斐波那契值(fibonaciiList[k])则是当前在left到right范围内数组的长度int k = 0;//找到该数组长度所位于斐波那契数列的位置索引k,再强调一下,斐波那契数列的每一个值我们都看成是数组的长度//现在要找的k,是当前数组长度在斐波那契数列中的位置索引while (arr.length > fibonaciiList[k]){k++;}//                          k//                          ↓//斐波那契数组:   {1,1,2,3,5,8,13,...},里面每一个值都看成是数组长度//斐波那契数组索引: [0,1,2,3,4,5, 6,...]//                          ↑//                          k//假设我们要找的数组是:{1,8,10,89,1000,1200},数组长度是6,那么该数组长度在斐波那契数列中对应的数组长度就应该是8//k是斐波那契数列的索引,所以k应该是5//如果当前k值对应的斐波那契值大于数组下标,则需要创建临时数组复制原数组并扩容至fibonaciiList[k]//再说一遍,斐波那契数组里面的每一个值都看成是数组的长度,那么,当前k所指向的斐波那契值是8,也就是要求要查找的数组arr需要有8个元素才符合对黄金分割点mid的计算int[] temp = Arrays.copyOf(arr, fibonaciiList[k]);//将填充的数据替换成arr的最后一个元素for (int i = arr.length; i < temp.length; i++) {temp[i] = arr[arr.length - 1];}//扩充并替换后的数组temp:{1,8,10,89,1000,1200,1200,1200}//mid是黄金分割点的索引int mid = 0;while (left <= right){//k == 0 说明当前查找的子序列只剩下一个元素。别忘了,k是斐波那契数列的下标,k==0说明f[k]==1,说明当前子序列长度为1if (k == 0){mid = left;}else {//斐波那契数组:   {1,1,2,3,5,8,13,...},里面每一个值都看成是数组长度//                          ↑//                          k//先摆公式      mid = left + f[k-1] -1//我们知道,黄金分割点mid的索引,其实是当前数组长度f[k],在斐波那契数列中位置的前一个斐波那契值f[k-1]//比如,当前数组长度是8,那么他的黄金分割比例就应该是5:3。再比如,如果当前数组长度是13,那么他的黄金分割比例应该是8:5//而黄金分割点mid,就是用来分割数组的,mid索引左右两边的子序列长度应该要满足黄金分割的比例//             left          mid  right//               ↓            ↓   ↓//数组temp:      {1,8,10,89,1000,1200,1200,1200}//temp数组索引:   [0,1, 2, 3,  4 , 5  ,  6 , 7  ]//                           ↑//                          mid//也就是说,我们应该要保证   mid的左子序列(包含mid)要有5个元素,  mid的右子序列(不包含mid)要有3个元素//所以黄金分割点按照上面的分析应该是mid = f[k-1] = 5,但是公式 mid = left + f[k-1] - 1 ,为什么最后还要再减1呢?//很显然,别忘记我们编程世界里的数组下标都是从0开始的,temp数组的索引是从0开始的,如果我们直接把f[k-1]当成mid的索引,显然不符合黄金分割比例的mid = left + fibonaciiList[k - 1] - 1;}if (target == temp[mid]){//如果temp[mid]就是目标值,而且当前mid不在扩充区就直接返回mid索引,否则返回right索引//                                 left//                                   ↓//比如数组temp:      {1,8,10,89,1000,1200,1200,1200} ,显然最后两个元素是扩充区,是原本arr数组没有的//                                   ↑    ↑//                                right  mid//这里说一下为什么mid会跑到left跟right的限定范围外?//因为当我们要找的目标值大于temp[mid]的时候,想要向右找子序列只会动left索引,right索引并不会去动它,计算出来的mid值是有可能超过left的,所以就可能会出现上面这种情况if (mid <= right) {return mid;}else {return right;}} else if (target < temp[mid]) {//目标值小于mid,向左找//这里解释为什么要k--?//                          k//                          ↓//斐波那契数组:   {1,1,2,3,5,8,13,...},里面每一个值都看成是数组长度//数组temp:      {1,8,10,89,1000,1200,1200,1200}//               ↑           ↑    ↑//             left         mid  right//因为当前数组长度是8,那么按照黄金分割比例,应该是mid左边(含mid)有五个元素,mid右边(不含mid)有3个元素//当我们想往左找目标值的时候,刚好k-1对应的斐波那契值就是5,而左边的子序列长度就是4,这时候就不需要扩容操作了,因为后面有元素,不会出现数组下标越界的情况//k--就是为了下一次循环做准备right = mid - 1;k--;} else if (target > temp[mid]) {//目标值大于mid,向右找//同往左找同理,往右找为什么需要k-2 ?//因为mid右边的子序列长度是3,刚好k-2对应的斐波那契值就是3,这样k=k-2就能保证我们下一次循环的k能够跟子序列数组长度3对应上left = mid + 1 ;k -= 2;}}//能出循环说明没找到目标值return -1;}/*** 获取斐波那契数列* @return*/public static int[] getFibonaciiList(int maxSize){int[] fibonaciiList = new int[maxSize];fibonaciiList[0] = 1;fibonaciiList[1] = 1;for (int i = 2; i < fibonaciiList.length; i++) {fibonaciiList[i] = fibonaciiList[i - 1] + fibonaciiList[i - 2];}return fibonaciiList;}
}

这篇关于[JDK17]斐波那契查找算法的实现原理、公式由来以及代码的实现(代码详解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/847335

相关文章

MySQL 8 中的一个强大功能 JSON_TABLE示例详解

《MySQL8中的一个强大功能JSON_TABLE示例详解》JSON_TABLE是MySQL8中引入的一个强大功能,它允许用户将JSON数据转换为关系表格式,从而可以更方便地在SQL查询中处理J... 目录基本语法示例示例查询解释应用场景不适用场景1. ‌jsON 数据结构过于复杂或动态变化‌2. ‌性能要

Python实现终端清屏的几种方式详解

《Python实现终端清屏的几种方式详解》在使用Python进行终端交互式编程时,我们经常需要清空当前终端屏幕的内容,本文为大家整理了几种常见的实现方法,有需要的小伙伴可以参考下... 目录方法一:使用 `os` 模块调用系统命令方法二:使用 `subprocess` 模块执行命令方法三:打印多个换行符模拟

SpringBoot+EasyPOI轻松实现Excel和Word导出PDF

《SpringBoot+EasyPOI轻松实现Excel和Word导出PDF》在企业级开发中,将Excel和Word文档导出为PDF是常见需求,本文将结合​​EasyPOI和​​Aspose系列工具实... 目录一、环境准备与依赖配置1.1 方案选型1.2 依赖配置(商业库方案)二、Excel 导出 PDF

Python实现MQTT通信的示例代码

《Python实现MQTT通信的示例代码》本文主要介绍了Python实现MQTT通信的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 安装paho-mqtt库‌2. 搭建MQTT代理服务器(Broker)‌‌3. pytho

MySQL字符串常用函数详解

《MySQL字符串常用函数详解》本文给大家介绍MySQL字符串常用函数,本文结合实例代码给大家介绍的非常详细,对大家学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql字符串常用函数一、获取二、大小写转换三、拼接四、截取五、比较、反转、替换六、去空白、填充MySQL字符串常用函数一、

Java中Arrays类和Collections类常用方法示例详解

《Java中Arrays类和Collections类常用方法示例详解》本文总结了Java中Arrays和Collections类的常用方法,涵盖数组填充、排序、搜索、复制、列表转换等操作,帮助开发者高... 目录Arrays.fill()相关用法Arrays.toString()Arrays.sort()A

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

Python 字典 (Dictionary)使用详解

《Python字典(Dictionary)使用详解》字典是python中最重要,最常用的数据结构之一,它提供了高效的键值对存储和查找能力,:本文主要介绍Python字典(Dictionary)... 目录字典1.基本特性2.创建字典3.访问元素4.修改字典5.删除元素6.字典遍历7.字典的高级特性默认字典

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

MySQL 主从复制部署及验证(示例详解)

《MySQL主从复制部署及验证(示例详解)》本文介绍MySQL主从复制部署步骤及学校管理数据库创建脚本,包含表结构设计、示例数据插入和查询语句,用于验证主从同步功能,感兴趣的朋友一起看看吧... 目录mysql 主从复制部署指南部署步骤1.环境准备2. 主服务器配置3. 创建复制用户4. 获取主服务器状态5