【算法系列 | 12】深入解析查找算法之—斐波那契查找

news2024/11/14 19:32:30

序言

心若有阳光,你便会看见这个世界有那么多美好值得期待和向往。

决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。

我们一起努力,成为更好的自己!

今天第12讲,讲一下查找算法的—斐波那契查找

一、算法介绍

斐波那契查找算法是一种基于黄金分割的有序查找算法,通过斐波那契数列的特性,在有序序列中快速定位目标元素的位置。

1.1 原理介绍

它结合了二分查找和黄金分割的思想。这个算法的基本原理如下:

  1. 序列构建: 首先,需要一个有序的数组或序列。这个数组的长度通常是斐波那契数列中的一个值,这有助于在查找过程中对数组进行分割。

  2. 斐波那契数列: 斐波那契数列是一组按以下递归关系定义的数字序列:F(0) = 0,F(1) = 1,F(n) = F(n-1) + F(n-2)(n > 1)。通常,斐波那契数列的前几项是:0, 1, 1, 2, 3, 5, 8, 13, 21, ...

  3. 查找过程: 对于一个有序序列,首先选择一个斐波那契数列中的值,使得这个值大于或等于待查找序列的长度,然后使用这个斐波那契数列的值将序列分成两个部分。这两个部分的长度之比就是相邻两个斐波那契数的比例。

  4. 比较: 比较要查找的元素与序列中分割点的元素。如果相等,则找到了目标元素;如果待查找元素小于分割点元素,继续在前半部分进行查找;如果待查找元素大于分割点元素,继续在后半部分进行查找。

  5. 迭代: 重复上述步骤,不断缩小查找范围,直到找到目标元素或确定元素不在序列中。

示例说明

假设有一个有序数组 arr,长度为 n,而 n 正好是斐波那契数列中的某个值。为了简化,我们可以选择 n 为斐波那契数列中的某个值,比如 F(5) = 5,所以 n = 5。那么,我们有一个有序数组 arr,长度为 5。

arr = [1, 3, 5, 7, 9]

接下来,我们要查找值为 5 的元素在数组中的位置。以下是斐波那契查找的步骤:

1. 选择斐波那契数列的值: 在斐波那契数列中找到一个最小的值,使得 F(k) >= n,其中 k 是最小可能满足的索引。在这个例子中,我们选择 F(5) = 5。

 2. 分割数组: 将数组分成两个部分,长度比例为斐波那契数列中的两个相邻值的比例。在这个例子中,我们有两部分,长度比例是 3:2。

     arr_left = [1, 3, 5] arr_right = [7, 9]

3.  比较与查找: 比较要查找的元素(5)与分割点元素(arr[2] = 5)。如果相等,找到了目标元素。如果待查找元素小于分割点元素,继续在前半部分进行查找。如果待查找元素大于分割点元素,继续在后半部分进行查找。

 在这个例子中,5 等于分割点元素,所以我们找到了目标元素的位置。

4. 迭代: 重复上述步骤,直到找到目标元素或确定元素不在序列中。

1.2 优缺点

优点:

  1. 适用性广泛: 斐波那契查找适用于有序序列,尤其在序列长度接近斐波那契数列的某个值时效果更佳。相较于二分查找,斐波那契查找能够在某些特定情况下减少查找次数。

  2. 更好的平衡: 由于斐波那契查找使用黄金分割比例进行分割,使得分割后的两个子序列的长度比例更加接近,有助于保持查找的平衡性。

  3. 相对均匀的分割: 斐波那契查找相对于其他分割方法,如二分查找,能够产生更为均匀的分割,有助于在查找过程中更快地接近目标元素。

缺点:

  1. 数组长度限制: 斐波那契查找要求待查找的序列长度必须是斐波那契数列中的某个值,这在实际应用中可能不太灵活,特别是当数据规模不是恰好是斐波那契数列中的某个值时,可能需要对数据进行补齐。

  2. 比较次数不稳定: 斐波那契查找在某些情况下可能会比二分查找效果更好,但并不是在所有情况下都表现更好。具体的性能取决于待查找数据的分布情况和序列的长度。在一些场景下,二分查找可能更为稳定。

  3. 计算斐波那契数列: 为了选择合适的斐波那契数列的值,需要事先计算斐波那契数列,这可能涉及到一些计算成本,特别是对于较大的数据集。

总体来说,斐波那契查找算法在某些特定条件下表现优秀,但在实际应用中需要谨慎选择,并根据具体情况考虑使用。在一些情况下,简单的二分查找可能更加实用和高效。

1.3 复杂度

时间复杂度:

  1. 查找过程: 斐波那契查找的主要操作是不断地缩小查找范围,通过比较待查找元素与分割点元素来确定继续在前半部分还是后半部分进行查找。在每一步操作中,都可以将待查找范围缩小为原来的黄金分割比例,即约为 0.618

  2. 时间复杂度: 斐波那契查找的时间复杂度可以表示为 O(log n),其中 n 是待查找序列的长度。与二分查找相比,它的复杂度相对更低。

空间复杂度:

  1. 常数空间: 斐波那契查找算法的空间复杂度非常低。它只需要常数级别的额外空间来存储一些中间变量,如斐波那契数列的值、分割点等。

  2. O(1): 因此,斐波那契查找的空间复杂度可以表示为 O(1)。

总体来说,斐波那契查找在时间复杂度和空间复杂度上都相对较低,这使得它在某些特定场景下成为一个有效的查找算法。

但需要注意,实际效果还受到数据分布等因素的影响,因此在选择查找算法时,需要综合考虑具体情况。

1.4 使用场景

斐波那契查找算法在一些特定的场景下表现良好,适用于如下情况:

  1. 有序序列: 斐波那契查找要求待查找的序列是有序的,因为它是基于比较来缩小查找范围的。如果序列无序,需要先进行排序操作。

  2. 长度接近斐波那契数: 算法对序列的长度有一定的要求,最好是恰好是斐波那契数列中的某个值。在实际应用中,可以选择最接近并大于待查找序列长度的斐波那契数。

  3. 分布均匀: 如果数据在序列中的分布相对均匀,斐波那契查找可以更好地发挥其优势。这是因为它能够在分割序列时保持更好的平衡。

  4. 查找频繁但数据变动不频繁: 如果对同一序列进行多次查找而且序列基本保持不变,斐波那契查找的一些前期计算可以提前完成,然后多次使用相同的计算结果进行查找,从而提高效率。

  5. 适用于内存有限的情况: 斐波那契查找只需要常数级别的额外空间,因此在内存有限的情况下比一些其他算法更为适用。

需要注意的是,斐波那契查找并不总是比其他查找算法更好,它在特定的条件下才会表现出色。在实际应用中,需要根据具体情况选择最适合的查找算法。

二、代码实现

2.1 Java代码实现

2.1.1 代码示例

public class FibonacciSearch {

    // 辅助函数:生成斐波那契数列
    private static int[] generateFibonacci(int n) {
        int[] fibonacci = new int[n];
        fibonacci[0] = 0;
        fibonacci[1] = 1;

        for (int i = 2; i < n; i++) {
            fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
        }

        return fibonacci;
    }

    // 斐波那契查找算法
    public static int fibonacciSearch(int[] arr, int key) {
        int n = arr.length;
        
        // 生成斐波那契数列,找到最接近且大于等于 n 的值
        int[] fibonacci = generateFibonacci(n);
        int k = 0;
        while (fibonacci[k] < n) {
            k++;
        }

        // 将数组扩展到斐波那契数列的长度
        int[] temp = new int[fibonacci[k]];
        System.arraycopy(arr, 0, temp, 0, n);

        int low = 0;
        int high = n - 1;

        // 主要查找过程
        while (low <= high) {
            int mid = low + fibonacci[k - 1] - 1;

            if (key < temp[mid]) {
                high = mid - 1;
                k -= 1;
            } else if (key > temp[mid]) {
                low = mid + 1;
                k -= 2;
            } else {
                // 找到了目标元素,需要判断返回的是原数组中的索引还是扩展数组中的索引
                return Math.min(mid, high);
            }
        }

        // 未找到目标元素
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 15};
        int key = 7;

        int result = fibonacciSearch(arr, key);

        if (result != -1) {
            System.out.println("元素 " + key + " 在数组中的索引为:" + result);
        } else {
            System.out.println("元素 " + key + " 不在数组中");
        }
    }
}

2.1.2 代码详解

  1. generateFibonacci方法:生成斐波那契数列,参数 n 表示生成数列的长度。

  2. fibonacciSearch方法:实现了斐波那契查找算法。首先,通过调用 generateFibonacci 方法生成斐波那契数列,然后找到最接近并大于等于数组长度的斐波那契数。接着,将原数组扩展到斐波那契数列的长度,再进行主要的查找过程。查找过程中,根据比较的结果不断缩小查找范围,直到找到目标元素或确定元素不在序列中。

  3. main方法:在这里,创建一个有序数组 arr,并调用 fibonacciSearch 方法查找元素 7 的索引。最后,输出查找结果。

2.1.3 运行结果

元素 7 在数组中的索引为:3

2.2 Python代码实现

2.2.1 代码示例

def generate_fibonacci(n):
    """生成斐波那契数列"""
    fibonacci = [0, 1]
    while fibonacci[-1] < n:
        fibonacci.append(fibonacci[-1] + fibonacci[-2])
    return fibonacci


def fibonacci_search(arr, key):
    """斐波那契查找算法"""
    n = len(arr)

    # 生成斐波那契数列,找到最接近且大于等于 n 的值
    fibonacci = generate_fibonacci(n)
    k = 0
    while fibonacci[k] < n:
        k += 1

    # 将数组扩展到斐波那契数列的长度
    temp = arr + [arr[-1]] * (fibonacci[k] - n)

    low, high = 0, n - 1

    # 主要查找过程
    while low <= high:
        mid = low + fibonacci[k - 1] - 1

        if key < temp[mid]:
            high = mid - 1
            k -= 1
        elif key > temp[mid]:
            low = mid + 1
            k -= 2
        else:
            # 找到了目标元素,返回原数组中的索引
            return min(mid, n - 1)

    # 未找到目标元素
    return -1

if __name__ == '__main__':

    # 测试
    arr = [1, 3, 5, 7, 9, 11, 13, 15]
    key = 7
    
    result = fibonacci_search(arr, key)

    if result != -1:
        print(f"元素 {key} 在数组中的索引为:{result}")
    else:
        print(f"元素 {key} 不在数组中")

2.2.2 代码详解

  1. generate_fibonacci 函数:用于生成斐波那契数列,直到数列的最后一个值大于等于给定的参数 n

  2. fibonacci_search 函数:实现了斐波那契查找算法。首先,调用 generate_fibonacci 函数生成斐波那契数列,然后找到最接近并大于等于数组长度的斐波那契数。接着,将原数组扩展到斐波那契数列的长度,再进行主要的查找过程。查找过程中,根据比较的结果不断缩小查找范围,直到找到目标元素或确定元素不在序列中。

在测试部分,创建一个有序数组 arr,并调用 fibonacci_search 函数查找元素 7 的索引。最后,输出查找结果。

2.2.3 运行结果

元素 7 在数组中的索引为:3

好啦,今天就到这里啦,下期见喽~~🙉

三、图书推荐

3.1 图书名称

图书名称:《Pandas数据分析》

Pandas是强大且流行的库,是Python中数据科学的代名词。这本书会介绍如何使用Pandas对真实世界的数据集进行数据分析,如股市数据、模拟黑客攻击的数据、天气趋势、地震数据、葡萄酒数据和天文数据等

Pandas使我们能够有效地处理表格数据,从而使数据整理和可视化变得更容易。等不及的小伙伴,可以点击这个链接先睹为快 《Pandas数据分析》

3.2 图书介绍 

3.3 参与方式

图书数量:本次送出 2 本   !!!⭐️⭐️⭐️
活动时间:截止到 2024-01-09 12:00:00

抽奖方式:

  • 评论区随机抽取小伙伴!

留言内容,以下方式都可以:

  • 根据文章内容进行高质量评论

参与方式:关注博主、点赞、收藏,评论区留言 

3.4 中奖名单

🍓🍓 获奖名单🍓🍓

 中奖名单:请关注博主动态

名单公布时间:2024-01-09 下午

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1360769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring模块(二)IOC容器之BeanFactory

在Spring中实现控制反转的是IoC容器 &#xff08;1&#xff09;IoC 不是一种技术&#xff0c;只是一种思想&#xff0c;一个重要的面向对象编程的法则&#xff0c;它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象&#xff0c;从…

AI与5G、IDC等成为数字经济的重要基础设施

AI与5G、IDC等已经成为数字经济的重要基础设施&#xff0c;它们的影响和作用不容忽视。随着技术的迅速发展&#xff0c;AI在各行各业都得到了广泛应用&#xff0c;并成为数字经济的核心驱动力之一。 首先&#xff0c;AI的兴起为数字经济带来了巨大的机遇。AI技术可以帮助企业从…

项目实战:数字孪生可视化大屏幕,实现生产过程实时监控

项目介绍 智慧工厂数据可视化系统&#xff0c;融合工业大数据、物联网、人工智能等各类信息技术&#xff0c;整合厂区现有信息系统的数据资源&#xff0c;实现数字孪生工厂、设备运维监测、智能管网监测、综合安防监测、便捷通行监测、能效管理监测、生产管理监测、仓储物流监…

Unity添加所有场景到BuildSettings

Unity添加所有场景到BuildSettings using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.IO; public class Tools : Editor {[MenuItem("Tools/添加所有场景到BuildSettings")]static void CheckSceneSetting(){List<string&…

【Linux Shell】6. echo 命令

文章目录 【 1. 显示普通字符串 】【 2. 显示转义字符 】【 3. 显示变量 】【 4. 显示换行 】【 5. 显示不换行 】【 6. 显示命令执行结果 】 Shell 的 echo 指令用于字符串的输出。命令格式&#xff1a; echo string【 1. 显示普通字符串 】 #!/bin/bashecho "It is a …

【STM32】STM32学习笔记-ADC模数转换器(21)

00. 目录 文章目录 00. 目录01. ADC简介02. ADC主要特征03. 逐次逼近型ADC04. ADC功能描述05. ADC基本结构06. 输入通道07. 转换模式08. 触发控制09. 数据对齐10. 转换时间11. 校准12. 硬件电路13. 附录 01. ADC简介 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F1…

2023 hnust 湖南科技大学 大四上 计算机图形图像技术 课程 期末考试 复习资料

计算机图形图像技术复习资料 前言 改编自&#xff1a;https://blog.csdn.net/Liu_Xin233/article/details/135232531★重点&#xff0c;※补充github 考试题型 简述题&#xff08;10分4题&#xff0c;共40分&#xff09; 第1章的基本内容三维观察流水线中的基本概念与理解三…

Linux第19步_安装“Ubutun交叉编译工具链”

由于Ubuntu系统使用的GCC编译器&#xff0c;编译结果是X86文件&#xff0c;只能在X86上运行&#xff0c;不能在ARM上直接运行。因此&#xff0c;还要安装一个“Ubutun交叉编译工具链”&#xff0c;才可以在ARM上运行。 arm-none-linux-gnueabi-gcc是 Codesourcery 公司&#x…

计算机组成原理 指令流水线

文章目录 指令流水线指令流水线的概念流水线性能分析流水线的吞吐率流水线的加速比流水线的效率 影响流水线的因素结构相关 (资源冲突)数据相关 (数据冲突)控制相关 (控制冲突) 流水线分类超量流水线 指令流水线 #mermaid-svg-vSsJnNqZf24LgjVK {font-family:"trebuchet m…

Ubuntu20.04安装ROS2 Foxy

Ubuntu20.04安装ROS2 Foxy 实操安装 安装ROS2的教程在网上很多&#xff0c;但是我操作之后都有问题&#xff0c;大部分的问题是在 sudo apt update 时访问packages.ros.org无法成功&#xff0c;主要的原因是没有外网&#xff0c;而自己整一个外网代理又非常麻烦&#xff0c;所…

即插即用篇 | YOLOv8 Gradio 前端展示页面 | 支持 【分类】【检测】【分割】【关键点】 任务

分类任务效果 分割任务效果 检测任务效果 关键点任务效果 使用方法 Gradio 是一个开源库,旨在为机器学习模型提供快速且易于使用的网页界面。它允许开发者和研究人员轻松地为他们的模型创建交互式的演示,使得无论技术背景如何的人都可以方便地试用和理解这些模型。使用Gradi…

二叉搜索树/二叉排序树(代码实现)(c++)

BSTree 二叉排序树概念代码部分 BSTree框架查找操作插入操作删除操作**默认成员函数完整代码 BSTree性能分析 二叉排序树概念 二叉搜索树又称二叉排序树&#xff08;BSTree, Binary Search Tree&#xff09;&#xff0c;它或者是一颗空树&#xff0c;或者是具有以下性质的二叉…

IP代理测试:关于Ping测试你需要知道的一切干货

您在访问互联网时是否遇到过持续滞后或花费很长时间等待网站加载的情况&#xff1f;为了避免这种情况&#xff0c;您可以测试 ping 以查看连接速度。如果您使用代理&#xff0c;此 ping 测试还会显示代理服务器的响应速度。 ping 测试是一个很有价值的工具&#xff0c;可以帮助…

武汉灰京文化:技术先锋辐射游戏行业,带来全新体验乐趣无穷!

科技的持续演进&#xff0c;给游戏产业打了强心剂&#xff0c;让这个领域变得前所未有的越来越好玩儿。今天我们将深入探讨如何利用虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;技术&#xff0c;让你玩得开心&#xff0c;玩得尽兴。 想象一下&…

目标检测 | YOLOv5 训练自标注数据集实现迁移学习

Hi&#xff0c;大家好&#xff0c;我是源于花海。本文主要了解 YOLOv5 训练自标注数据集&#xff08;自行车和摩托车两种图像&#xff09;进行目标检测&#xff0c;实现迁移学习。YOLOv5 是一个非常流行的图像识别框架&#xff0c;这里介绍一下使用 YOLOv5 给使用 Labelme 标注…

【DevOps-07-2】Sonarqube基本使用

一、简要说明 Sonar Qube的使用方式很多&#xff0c;Maven可以整合&#xff0c;也可以采用sonar-scanner的方式&#xff0c;再查看Sonar Qube的检测效果 Sonarqube集成在Maven实现代码检测使用sonar-scanner客户端的方式 二、Sonarqube管理后台安装中文插件 1、登录Sonarqube管…

Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models

ABSTRACT 现代大规模视觉-语言模型&#xff08;LVLMs&#xff09;采用了相同的视觉词汇-CLIP&#xff0c;可以涵盖大多数常见的视觉任务。然而&#xff0c;对于一些需要密集和细粒度视觉感知的特殊视觉任务&#xff0c;例如文档级OCR或图表理解&#xff0c;尤其是在非英语环境…

用通俗易懂的方式讲解:ChatGPT 开放的多模态的DALL-E 3功能,好玩到停不下来!

最近 ChatGPT 对 Plus 用户逐步开放一些多模态的功能&#xff0c;包括 &#xff08;图像生成&#xff09;、 GPT-4V&#xff08;图像识别&#xff09;等&#xff0c;很多网友乐此不疲地对这些新功能进行试用&#xff0c; 目前已经解锁了不少有趣的玩法&#xff0c;我将这些好玩…

软件测试/测试开发丨Vuetify框架的使用

介绍 Vuetify 是一个基于 Vue.js 精心打造 UI 组件库&#xff0c;整套 UI 设计为 Material 风格。能够让没有任何设计技能的开发者创造出时尚的 Material 风格界面。 为什么要使用Vuetify框架 所有组件遵从 Material Design 设计规范&#xff0c;UI 体验非常优秀&#xff0c…

FindMy技术用于键盘

键盘是我们生活中不可或缺的输入工具&#xff0c;是人与计算机之间沟通的桥梁&#xff0c;无论是编写文档、浏览网页、玩游戏、或是进行复杂的数据分析&#xff0c;键盘都在其中发挥着关键的作用。此外&#xff0c;键盘还是各种软件的快捷键操作的关键。通过熟练地运用快捷键&a…