斐波那契查找:用黄金比例快速定位目标

斐波那契查找的生动形象解释——“用斐波那契数列来分割蛋糕”

想象你和朋友有一条长长的蛋糕,你们想找出蛋糕中某个特别的点(比如夹心的位置)。蛋糕上有很多均匀排列的标记,你们要快速找到目标标记。


传统的二分查找

  • 你们先把蛋糕从中间切开,
  • 看目标在左边还是右边,
  • 然后继续对半切,
  • 一次次折半缩小范围。

斐波那契查找的聪明切法

  • 你们用斐波那契数列来决定切蛋糕的位置,
  • 斐波那契数列是这样的数列:1, 1, 2, 3, 5, 8, 13, 21, …
  • 你们先找一个斐波那契数,刚好比蛋糕长度稍大,
  • 然后用这个数来决定切蛋糕的位置,
  • 这样切的位置不是简单的中间,而是根据斐波那契数列比例来切,
  • 这样能更灵活地缩小查找范围。

具体比喻

假设蛋糕长度是21块,斐波那契数列中21是一个数。

  • 你先用第一个斐波那契数13来切蛋糕,
  • 看目标在13块之前还是之后,
  • 如果目标在前面,你用斐波那契数8继续切,
  • 如果目标在后面,你用斐波那契数5继续切,
  • 依次用斐波那契数列的数来缩小范围。

为什么用斐波那契数列?

  • 斐波那契数列的比例接近黄金分割比例(约0.618),
  • 这种比例切分能让查找过程更均匀,减少不必要的比较,
  • 适合在某些情况下比二分查找更高效。

斐波那契查找的优点

  • 不需要除法运算,只有加减法,适合计算代价高的环境。
  • 利用斐波那契数列的性质,减少查找次数。
  • 对于某些硬件或存储结构,访问代价不均匀时表现更好。

小结

斐波那契查找就像用斐波那契数列的“黄金比例”来切蛋糕,聪明地决定每次切的位置,快速找到目标。


我们继续深入讲解斐波那契查找,帮你更全面理解它的工作原理和应用场景。


斐波那契查找的详细过程

假设你有一个升序排列的数组,长度为n,你要查找目标值key


1. 找到最小的斐波那契数F[k],使得F[k] >= n

  • 斐波那契数列是:1, 1, 2, 3, 5, 8, 13, 21, 34, …
  • 例如,数组长度是20,找到F[8] = 21,因为21 >= 20。

2. 初始化变量

  • offset = -1,表示已排除的前面元素的索引
  • k 是斐波那契数的索引

3. 进行查找

  • 比较arr[min(offset + F[k-2], n-1)]key
  • 如果key大于该值,说明目标在右边,更新:
    • offset = offset + F[k-2]
    • k = k - 1
  • 如果key小于该值,说明目标在左边,更新:
    • k = k - 2
  • 如果相等,查找成功,返回索引。

4. 重复步骤3,直到k变为0或找到目标


斐波那契查找的示意图

假设数组长度是21,斐波那契数是21:

数组索引: 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20
斐波那契数:       F[k] = 21
第一次比较位置: offset + F[k-2] = -1 + F[6] = -1 + 13 = 12
  • 比较arr[12]key,根据结果调整offsetk,继续查找。

斐波那契查找的优缺点

优点缺点
只用加减法,不用除法,计算简单需要预先计算斐波那契数列
利用黄金分割比例,查找效率高适用范围有限,数组必须有序
对某些存储结构访问效率更好实现比二分查找稍复杂

生活中的类比

  • 二分查找:像你把书架从中间分开找书。
  • 斐波那契查找:像你用黄金比例分割书架,先去大约0.618处找,
    如果没找到,再用更小的斐波那契数分割剩下的部分,
    这样分割更符合自然规律,查找更高效。

斐波那契查找的应用场景

  • 适合在计算除法代价高的硬件环境。
  • 适合访问代价不均匀的存储结构,比如磁盘或分布式存储。
  • 适合对有序数组进行快速查找。

代码示例(Python)

def fibonacci_search(arr, key):
    n = len(arr)
    # 初始化斐波那契数
    fibMMm2 = 0  # (m-2)'th Fibonacci No.
    fibMMm1 = 1  # (m-1)'th Fibonacci No.
    fibM = fibMMm2 + fibMMm1  # m'th Fibonacci

    # 找到最小的fibM >= n
    while fibM < n:
        fibMMm2 = fibMMm1
        fibMMm1 = fibM
        fibM = fibMMm2 + fibMMm1

    offset = -1

    while fibM > 1:
        i = min(offset + fibMMm2, n - 1)

        if arr[i] < key:
            fibM = fibMMm1
            fibMMm1 = fibMMm2
            fibMMm2 = fibM - fibMMm1
            offset = i
        elif arr[i] > key:
            fibM = fibMMm2
            fibMMm1 = fibMMm1 - fibMMm2
            fibMMm2 = fibM - fibMMm1
        else:
            return i

    if fibMMm1 and offset + 1 < n and arr[offset + 1] == key:
        return offset + 1

    return -1

# 测试
arr = [10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100]
key = 85
index = fibonacci_search(arr, key)
print(f"元素{key}的索引是: {index}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值