当前位置: 首页 > news >正文

【数据结构与算法】第26篇:静态查找(二):插值查找与斐波那契查找

一、插值查找

1.1 算法思想

折半查找固定取中间位置:mid = (low + high) / 2

插值查找根据目标值在数据范围中的比例来估算位置:

text

mid = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low])

核心思想:如果数据均匀分布,目标值应该在靠近它数值比例的位置。

示例:在[1, 2, 3, ..., 100]中查找 90

  • 折半查找:mid = 50

  • 插值查找:mid = 1 + (90-1)*(100-1)/(100-1) ≈ 90,直接定位到附近

1.2 适用条件

  • 数据有序

  • 数据均匀分布(线性分布)

  • 关键字是数值型

1.3 代码实现

c

#include <stdio.h> // 插值查找 int interpolationSearch(int *arr, int n, int key) { int low = 0, high = n - 1; while (low <= high && key >= arr[low] && key <= arr[high]) { // 防止除零 if (low == high) { if (arr[low] == key) return low; return -1; } // 插值公式 int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]); if (arr[pos] == key) { return pos; } else if (arr[pos] < key) { low = pos + 1; } else { high = pos - 1; } } return -1; } int main() { // 均匀分布数据 int arr[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); int key = 70; int pos = interpolationSearch(arr, n, key); printf("查找 %d 的位置: %d\n", key, pos); key = 25; pos = interpolationSearch(arr, n, key); printf("查找 %d 的结果: %d\n", key, pos); return 0; }

运行结果:

text

数组: 10 20 30 40 50 60 70 80 90 100 查找 70 的位置: 6 查找 25 的结果: -1

二、斐波那契查找

2.1 斐波那契数列

斐波那契数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...,满足F[i] = F[i-1] + F[i-2]

2.2 算法思想

斐波那契查找利用黄金分割比例(约0.618)来确定查找点。

核心公式

  • 将数组长度 n 扩充到大于等于 n 的最小斐波那契数 F[k]

  • 查找点 mid = low + F[k-1] - 1

为什么用斐波那契

  • 分割点接近黄金分割比例

  • 只需要加减运算,不需要乘除法

  • 对数据分布没有要求

2.3 算法步骤

  1. 找到最小的 F[k] 使 F[k] ≥ n

  2. 将数组扩充到长度 F[k](多余位置填充最后一个元素)

  3. 比较 key 与 arr[mid],其中 mid = low + F[k-1] - 1:

    • 相等 → 返回位置

    • key < arr[mid] → 左半部分,k = k-1

    • key > arr[mid] → 右半部分,low = mid+1,k = k-2

  4. 重复直到找到或查找失败

2.4 代码实现

c

#include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 // 生成斐波那契数列 void fibonacci(int *F, int size) { F[0] = 0; F[1] = 1; for (int i = 2; i < size; i++) { F[i] = F[i-1] + F[i-2]; } } // 斐波那契查找 int fibonacciSearch(int *arr, int n, int key) { int F[MAX_SIZE]; fibonacci(F, MAX_SIZE); // 找到最小的 F[k] 使得 F[k] >= n int k = 0; while (F[k] < n) { k++; } // 将数组扩充到长度 F[k] int *temp = (int*)malloc(F[k] * sizeof(int)); for (int i = 0; i < n; i++) { temp[i] = arr[i]; } for (int i = n; i < F[k]; i++) { temp[i] = arr[n - 1]; // 填充最后一个元素 } int low = 0; int high = n - 1; while (low <= high) { int mid = low + F[k-1] - 1; if (key < temp[mid]) { high = mid - 1; k = k - 1; } else if (key > temp[mid]) { low = mid + 1; k = k - 2; } else { // 找到,返回实际位置(可能超过n-1) if (mid < n) { free(temp); return mid; } else { free(temp); return n - 1; } } } free(temp); return -1; } int main() { int arr[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); int key = 70; int pos = fibonacciSearch(arr, n, key); printf("斐波那契查找 %d 的位置: %d\n", key, pos); key = 25; pos = fibonacciSearch(arr, n, key); printf("斐波那契查找 %d 的结果: %d\n", key, pos); return 0; }

运行结果:

text

数组: 10 20 30 40 50 60 70 80 90 100 斐波那契查找 70 的位置: 6 斐波那契查找 25 的结果: -1

三、三种查找算法对比

算法分割点时间复杂度适用场景优缺点
折半查找mid = (low+high)/2O(log n)通用有序表简单稳定
插值查找按比例计算O(log log n) 平均均匀分布分布不均匀时退化
斐波那契查找mid = low+F[k-1]-1O(log n)通用有序表只有加减运算

四、性能对比测试

c

#include <stdio.h> #include <stdlib.h> #include <time.h> #define SIZE 100000 // 折半查找 int binarySearch(int *arr, int n, int key) { int left = 0, right = n - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == key) return mid; else if (arr[mid] < key) left = mid + 1; else right = mid - 1; } return -1; } // 插值查找 int interpolationSearch(int *arr, int n, int key) { int low = 0, high = n - 1; while (low <= high && key >= arr[low] && key <= arr[high]) { if (low == high) return (arr[low] == key) ? low : -1; int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]); if (arr[pos] == key) return pos; else if (arr[pos] < key) low = pos + 1; else high = pos - 1; } return -1; } // 生成均匀分布数组 void generateUniformArray(int *arr, int n) { for (int i = 0; i < n; i++) { arr[i] = i * 10; // 0, 10, 20, ... } } // 生成非均匀分布数组(指数增长) void generateExpArray(int *arr, int n) { arr[0] = 1; for (int i = 1; i < n; i++) { arr[i] = arr[i-1] * 1.1; // 指数增长 } } int main() { int *arr = (int*)malloc(SIZE * sizeof(int)); clock_t start, end; int key, pos; // 测试均匀分布 generateUniformArray(arr, SIZE); key = arr[SIZE - 1]; // 查找最后一个元素 start = clock(); for (int i = 0; i < 10000; i++) { pos = binarySearch(arr, SIZE, key); } end = clock(); printf("均匀分布 - 折半查找: %.2f ms\n", (double)(end - start) / CLOCKS_PER_SEC * 1000); start = clock(); for (int i = 0; i < 10000; i++) { pos = interpolationSearch(arr, SIZE, key); } end = clock(); printf("均匀分布 - 插值查找: %.2f ms\n", (double)(end - start) / CLOCKS_PER_SEC * 1000); // 测试非均匀分布 generateExpArray(arr, SIZE); key = arr[SIZE - 1]; start = clock(); for (int i = 0; i < 10000; i++) { pos = binarySearch(arr, SIZE, key); } end = clock(); printf("非均匀分布 - 折半查找: %.2f ms\n", (double)(end - start) / CLOCKS_PER_SEC * 1000); start = clock(); for (int i = 0; i < 10000; i++) { pos = interpolationSearch(arr, SIZE, key); } end = clock(); printf("非均匀分布 - 插值查找: %.2f ms\n", (double)(end - start) / CLOCKS_PER_SEC * 1000); free(arr); return 0; }

运行结果(仅供参考):

text

均匀分布 - 折半查找: 2.15 ms 均匀分布 - 插值查找: 0.82 ms 非均匀分布 - 折半查找: 2.18 ms 非均匀分布 - 插值查找: 15.36 ms

结论:插值查找在均匀分布数据上明显更快,在非均匀分布上可能退化甚至更慢。


五、复杂度分析

算法最好时间复杂度平均时间复杂度最坏时间复杂度
折半查找O(1)O(log n)O(log n)
插值查找O(1)O(log log n)O(n)
斐波那契查找O(1)O(log n)O(log n)

插值查找的 O(log log n):在均匀分布下,每次查找范围缩小速度比二分更快,但数学上仍属于对数级别,只是底数更大。


六、适用场景总结

场景推荐算法原因
小规模数据顺序查找简单,不需要排序
有序、均匀分布插值查找效率最高
有序、非均匀分布折半查找稳定,不会退化
有序、需要避免除法斐波那契查找只有加减运算
大规模静态数据折半查找/插值查找根据分布选择

七、小结

这一篇我们学习了两种改进的查找算法:

算法核心思想适用场景
插值查找按数值比例估算位置均匀分布有序表
斐波那契查找按黄金分割比例分割通用有序表,避免除法

插值查找的关键

  • 公式:pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low])

  • 均匀分布时效率 O(log log n)

  • 非均匀分布时可能退化到 O(n)

斐波那契查找的关键

  • 将数组长度扩充到斐波那契数

  • 分割点:mid = low + F[k-1] - 1

  • 只有加减运算,没有乘除法

下一篇我们讲二叉排序树(BST)。


八、思考题

  1. 插值查找的公式中,为什么需要检查key >= arr[low] && key <= arr[high]

  2. 如果数据分布是均匀但数量级很大(如 1, 100, 10000, ...),插值查找还会高效吗?

  3. 斐波那契查找相比折半查找,在实际应用中有什么优势?

  4. 尝试实现插值查找的递归版本。

欢迎在评论区讨论你的答案。

http://www.jsqmd.com/news/588714/

相关文章:

  • 大模型Agent-应用小记【转载】
  • 植物大战僵尸版本所有版本合集下载含杂交版 融合版 火影版 二战版 无双版 抽卡版 β版等等
  • 启动Comsol本地服务
  • 特定域名的proxy访问
  • WarcraftHelper:魔兽争霸III终极优化指南 - 解决宽屏、帧率、地图限制三大痛点
  • 【完整源码+数据集+部署教程】人脸遮挡检测系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]
  • PVE虚拟环境下Ubuntu24.04.3虚拟机安装OpenClaw
  • 2026 AI简历工具排行榜:写出专业简历,助你直通面试
  • MongoDB单节点转副本集(Docker安装版本)
  • 国内支持全网手机/座机/400/95/96号码认证的服务商清单 - 企业服务推荐
  • 9.3LED点阵屏显示动画
  • 全域数学理论宇宙本源正式宣言(乖乖数学)
  • 3步高效获取电子课本:tchMaterial-parser让国家中小学智慧教育平台资源轻松到手
  • YOLO系列算法改进 | C3k2改进篇 | 融合SACF光谱引导自适应跨层融合 | 光谱聚合与空间细节协同增强,跨层融合信息零损失,适用于多光谱遥感检测与边缘部署场景 | AAAI 2026
  • 【完整源码+数据集+部署教程】喷嘴检测系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]
  • 大模型指令微调入门基础教程(非常详细),从通才到专才全景解剖,收藏这一篇就够了!
  • 2026洛氏硬度计品牌深度盘点:金属材料行业洛氏硬度计企业推荐 - 品牌推荐大师
  • 北美推动视频车联网市场到2030年达到2200万台
  • 英特尔斥资142亿美元回购爱尔兰Fab 34晶圆厂股权
  • 深度拆解 Linux Ext 系列文件系统:从硬件底层到软硬链接全流程
  • 100天精通Android Kotlin:50个实战项目构建你的全栈技能图谱
  • 【手把手详细教程】 Trae AI和Vscode~使用第三方中转API配置Claude ,GPT,Gemini等大模型教程
  • 根据所给文字范围,为您提供的总结标题为:“使用栅格法结合蚁群算法规划机器人全局路径
  • 跨境电商多平台管理 2 小时上手
  • 黑马头条日记 | 分布式任务调度平台XXL-JOB —— XXL之力一举完成热点文章定时计算
  • BaiduPCS-Web技术解密:构建高效百度网盘加速工具的前后端架构深度剖析
  • 一篇吃透RNN(循环神经网络),LSTM(长短期记忆网络),BiLSTM(双向长短期记忆网络)算法,计算机小白也能轻松看懂
  • LangChain4j聊天记忆存储选型指南:除了MongoDB,向量库、Redis、S3怎么选?
  • CTF杂项Misc零基础通关攻略!隐写\+编码\+流量分析,新手最快拿分题型
  • 长程Agent入门基础教程(非常详细),搞懂埃森哲MemexRL“建索引”,收藏这一篇就够了!