(d3)有序向量:Fibonacci查找
Fibonacci 查找
看完你能说清它为何比二分快、画出黄金分割切分点并推证明
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
Fibonacci 查找
看完你能说清它为何比二分快、画出黄金分割切分点并推证明
二分查找的遗留问题
上一页我们看到,二分查找很好用,但有个细节:每次比较其实要做一次判断相等、再判断往左还是往右,失败时比了两次。而左右两个分支的宽度还不相等——这遗留问题正是 Fibonacci 查找的切入点。
轻的一侧对应比较更省的方向,切分点应向代价高的一侧倾斜
前后分支不平衡
上页看到二分查找有三次比较:小于、大于、等于。中点命中概率很小,多数时间都在往左或往右走。那这两个方向的代价一样吗?数一数就会发现,左右并不公平。
左右两块一样大,但拿右边那块要绕两次手
让切分点偏后
上页结论:二分的两个分支深度不同,深的那条反而更常被走到。既然访问次数改不了,那就改变分法——把切分点往右挪,让常走的后段变短、变浅,代价自然降下来。
把更长的队排到通行更快的一侧,总耗时变短
黄金分割与 Fibonacci 数
上一页确认切分点要偏后,但偏到哪才恰到好处?把区间按黄金分割 0.618 切开:短段在前、长段在后。而这个比例,恰好能被 Fibonacci 数列越来越精确地逼近。
不断按比例折纸与不断用 Fib 相邻项作比,都收敛到 0.618
Fibonacci 数列与切分点
上一页我们看到,黄金分割能给出最合适的不平衡切分点。可是黄金分割比 0.618 是个无理数,比较时没法直接算——好在 Fibonacci 数列相邻两项之比,恰好会越来越逼近它。
正多边形边数增加逼近圆周率,如同 Fib 相邻项之比逼近 0.618
算法流程
Fibonacci 查找的每一轮:按 fib 数定切分点,比较后向左或向右收缩区间。
代码实现
用 Fibonacci 数定位切分点 k,按三种比较结果收缩区间,直至命中或区间为空。
切分点取 lo+fib[k-1],使前段短、后段长;命中右侧时按 fib[k-2] 收缩,两分支代价趋于均衡。
Fib 数的快速推进
上一页的代码里,切分点靠 fib(k) 定位。但每次查找都从 fib(1) 算到 fib(k) 太浪费——其实整个查找过程中,只需要相邻两个 Fib 数随分支同步推进就够了。
登山者的当前位置和剩余路程,对应 fib(k-1) 与 fib(k-2)
实例:完整查找过程
在长度为 12 的有序向量上查找目标,看 Fibonacci 查找如何逐步收缩区间。
实例的分段图示
从左往右看每个节点:方框内是当前向量宽度(Fib 数),箭头标注切分点 mi 位置,跟随箭头观察左右两支宽度如何递减。
自测:下一步切在哪
有序向量长 fib(k)-1,在 fib(k-1)-1 处切分后,若目标值大于切分元素,下一步在前段还是后段继续?宽度是多少?
平均查找长度的权衡
前面我们让切分点偏后,换来了更快的推进速度。但代价是什么?每一次查找走前后分支的概率和代价都不一样,真正要比较的是平均成本,而不是单步快慢。
切得偏一点,多数人拿大块,总量反而更省
二分 vs Fibonacci 查找
两者都是有序向量的减治查找,唯一差别在切分点位置——却直接决定比较次数的分布。
- 切分点固定取中点 mi = (lo+hi)/2
- 前后两个分支等宽、完全对称
- 每次比较成功概率相同,成本均摊
- 切分点按 Fibonacci 数偏后,约 0.618 处
- 前宽后窄,有意制造不平衡
- 先比较后宽段:多数元素一次即命中
最优性论证
上一页比较了两者效率,Fibonacci 查找略胜,但胜在哪里、有没有极限?关键在于:切口偏后让后段更短,比较次数被压到 O(logφn),而这个比例在数学上恰恰是最优的。
大箱走捷径(进入前段)、小箱抬着快跑,两边总耗时相等才最优
要点收束
- ✓深层成本在比较次数:转向成功查找,且转向更省,故切分点应偏后
- ✓黄金分割确定比例,Fib 数给出可实现的整数切分点
- ✓实现只用加减推进 fib,避免乘除,分界 case 需留意边界
- ✓平均复杂度同为 O(logn),但常数更小,且证明其已达最优
课后思考
三个问题没有唯一答案:先自己想几分钟,再对照参考答案。
参考答案思路:O(log n) 只数比较次数,而 Fibonacci 用加减代替除法取切点,且前后子问题规模按黄金比例递减,失败方向的代价更小。想想你的机器上除法与加减的真实开销。
参考答案把代价写进权衡:总代价 ≈ 左分支代价×左规模 + 右分支代价×右规模。代价不等时,最优点会偏离黄金分割——代价高的分支应分到更小的规模,试着推出偏移方向。
参考答案插值按"值域比例"预估位置,分布均匀时一次到位,不均匀时退化甚至比二分差。启示:比例切分的前提是"比例假设"成立——先问数据满足什么分布,再谈哪把刀更快。