059斐波那契查找

斐波那契查找 - 用加减法代替除法的二分变体

059斐波那契查找:不用除法的侦探

📰 5W1H 发明者故事

Who(何人)- 发明者是谁?

发明者 :贝茨(D. E. Ferguson,有时记为Betz)和卡特(J. Carter),1959年发表斐波那契查找算法。

背景:

  • 1950年代末,许多计算机的硬件除法指令要么不存在,要么速度极慢(比加减法慢10倍以上)
  • 斐波那契查找的核心动机是:用加减法(快速)代替除法(慢速)来计算分割点
  • 高德纳在TAOCP第三卷6.2.1节对其进行了完整的理论分析,给出精确的平均比较次数公式

When(何时)- 什么时候发明的?

时间 :1959年

时代背景:

  • IBM 704等早期计算机的浮点除法需要数十个时钟周期,而加减法只需1-2个周期
  • 二分查找(1946年)已成熟,但其核心操作 mid = (low + high) / 2 需要除法
  • 斐波那契数列(F(n) = F(n-1) + F(n-2))的递推关系恰好只用加减法

Where(何地)- 在哪里发明的?

地点 :美国,论文发表于ACM Communications(早期)

环境:

  • 早期商业计算机时代,硬件设计者尚未将除法列为必要指令
  • 嵌入式系统和早期微处理器(如Intel 8080)也缺乏硬件除法支持

What(何事)- 发明了什么?

算法 :斐波那契查找(Fibonacci Search)

核心概念:

  • 用斐波那契数 F(k) 来描述数组长度,以 F(k-1) 和 F(k-2) 来分割数组
  • 分割点 i = low + F(k-1) - 1,计算只需加减法
  • 两个子区间长度为 F(k-1)-1 和 F(k-2)-1(不完美均等,但避免了除法)

与二分查找的区别:

复制代码
二分查找:每次以 (low+high)/2 为分割点,需除法
斐波那契查找:每次以 low + F(k-1)-1 为分割点,只需加法
比较次数:斐波那契约为 1.44 log₂N,略多于二分查找的 log₂N

Why(何因)- 为什么发明?

要解决的问题:

  1. 早期计算机上除法是昂贵操作,二分查找因此受限
  2. 斐波那契数列天然满足"两项之和等于下一项",递推计算零除法
  3. 对于磁带顺序访问,斐波那契分割的步长更均匀,减少磁头移动

当时的挑战:

  • 斐波那契数不是任意大小,需要将数组补齐到最近的斐波那契数(用最大值或虚拟元素填充)
  • 分割不均匀(F(k-1) vs F(k-2))意味着平均比较次数略多于二分查找

How(何果)- 如何实现?有什么影响?

实现思路:

复制代码
预计算斐波那契表:F[0]=1, F[1]=1, F[2]=2, F[3]=3, F[4]=5, ...
找到最小的 k 使得 F[k] >= n
分割逻辑(以 F[k-2] 分割左子区间,F[k-1] 分割右子区间):
  if arr[i] < target: low = i+1, k -= 1 (右半,长度F[k-1]-1)
  if arr[i] > target: high = i-1, k -= 2 (左半,长度F[k-2]-1)
  if arr[i] == target: 找到

历史影响:

  • 成为嵌入式系统和早期微处理器的标准查找方法
  • 教科书中作为"算法不一定要用最自然的分割"的经典案例
  • 现代编译器和DSP处理器优化中,仍有类似的"避免除法"优化思路

今天的使用:

  • 无硬件除法指令的嵌入式微控制器(AVR, PIC等早期架构)
  • FPGA实现中的查找(减少DSP资源占用)
  • 教学场景:展示算法设计中硬件约束对算法形式的影响

名言:Knuth在TAOCP中评价:"斐波那契查找是一个优美的例子,展示了如何将数学上的递推结构与计算机的硬件约束相结合,创造出实用的算法。"


📝 自然语言需求定义

需求名称:实现斐波那契查找,仅用加减法完成有序数组查找

功能需求(用精确的中文描述)

  1. 斐波那契表预计算:预计算足够大的斐波那契数列

    • 输入:无(固定计算到F30以上)
    • 操作:F0=1, F1=1, Fi=Fi-1+Fi-2
    • 输出:静态数组
  2. 斐波那契查找:在有序数组中用斐波那契数分割查找

    • 输入:有序整数数组、元素个数、目标值
    • 操作:找到最小k使Fk>=n;以Fk-1为分割点;根据比较结果缩减k
    • 输出:找到返回下标,未找到返回-1
    • 约束:实现中不得使用除法运算符 /(演示无除法特性)
  3. 结果验证:与标准二分查找对比,两者对相同输入必须给出相同的"是否找到"结论

    • 输入:同一有序数组和目标值
    • 输出:两个下标(可以不同,但找到/未找到的结论必须一致)

约束条件

  • 核心查找循环不使用除法运算符(/ 或 %)
  • 数组保持只读(不修改原数组)
  • 支持空数组(n=0)返回-1
  • 斐波那契表大小足以处理 n <= 10000 的数组

验收标准(必须可验证)

编号 测试场景(自然语言描述) 预期结果 验证方式
1 在1,3,5,7,9,11,13,15,17,19中查找11 返回下标5 断言返回值
2 查找第一个元素1 返回下标0 断言返回值
3 查找最后一个元素19 返回下标9 断言返回值
4 查找不存在的元素6 返回-1 断言返回值
5 查找比最大值大的值100 返回-1 断言返回值
6 与二分查找结果一致(所有存在的元素) 找到/未找到结论一致 遍历断言
7 单元素数组42中查找42 返回0 断言返回值
8 单元素数组42中查找1 返回-1 断言返回值

AI 生成提示

复制代码
基于以上需求和验收标准,用标准C语言实现斐波那契查找。

要求:
1. 使用标准C99,gcc -Wall无警告
2. 预计算斐波那契表(静态数组,大小至少50)
3. 核心查找循环不使用/或%运算符
4. 同时实现标准二分查找用于对比验证
5. 完整测试框架:tests_passed/tests_failed计数
6. main最后返回 tests_failed > 0 ? 1 : 0

核心函数:
- fibonacci_search(arr, n, target) - 斐波那契查找,返回下标或-1
- binary_search_ref(arr, n, target) - 参考二分查找,用于对比

💻 C语言实现文件

对应文件 : fibonacci_search.c

编译运行:

bash 复制代码
gcc -std=c99 -Wall -o fibonacci_search_test fibonacci_search.c
./fibonacci_search_test

核心函数:

  • fibonacci_search(arr, n, target) - 斐波那契查找,仅用加减法,返回下标或-1
  • binary_search_ref(arr, n, target) - 参考用二分查找,用于验证结果一致性
相关推荐
北域码匠2 个月前
三分查找算法完整详解(C# 原生实现,无第三方库)
数值优化·分治算法·查找算法·编程基础·三分查找·c#算法·算法教程
71-35 个月前
C语言练习——数组的练习(涉及顺序、二分查找,冒泡排序)
c语言·笔记·学习·排序算法·查找算法
Kethy__6 个月前
计算机中级-数据库系统工程师-数据结构-查找算法
数据结构·算法·软考·查找算法·计算机中级
CappuccinoRose6 个月前
排序算法和查找算法 - 软考备战(十五)
数据结构·python·算法·排序算法·查找算法
大模型铲屎官2 年前
C语言数据结构:链表、栈与队列、排序算法与查找算法深度解析
c语言·数据结构·链表·排序算法·栈·队列·查找算法
梅见十柒2 年前
数据结构与算法分析——你真的理解查找算法吗——基于散列的查找(代码详解+万字长文)
java·c语言·c++·笔记·算法·哈希算法·查找算法
龙枫9952 年前
查找算法:线性查找,golang实现
golang·查找算法
TENET-2 年前
数据结构——查找算法
数据结构·算法·查找算法
TranquilGlow3 年前
常见的查找算法以及分块搜索算法的简明教程
java·算法·查找算法