斐波那契查找(黄金分割查找算法)

2023-10-24 13:30

本文主要是介绍斐波那契查找(黄金分割查找算法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 斐波那契
    • 一、摘要
    • 二、什么是斐波那契查找
    • 三、 基本思想
    • 四、举例
    • 五、如何计算
      • 1、斐波那契数组
      • 2、利用斐波那契数组确定元素的位置
      • 3、举例
    • 六、代码实现
      • 1、斐波那契数组实现
      • 2、斐波那契查找
      • 3、实验数据及测试
      • 4、编译环境
    • 七、后记

斐波那契

一、摘要

如果从文件中读取的数据记录的关键字是有序排列的(递增的或是递减的),则可以用一种比折半查找法更有效率的查找方法来查找文件中的记录,即为斐波那契查找,也称为黄金分割查找法。

二、什么是斐波那契查找

斐波那契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、····,在数学上,斐波那契被递归方法如下定义:F(1)=1,F(2)=1,F(n)=f(n-1)+F(n-2) (n>=2)。该数列越往后相邻的两个数的比值越趋向于黄金比例值(0.618)。

三、 基本思想

斐波那契查找法与折半查找的基本思想类似,都是减少查找序列的长度,分而治之地进行关键字的查找。他的查找过程是:先确定待查找记录的所在的范围,然后逐渐缩小查找的范围,直至找到该记录为止(也可能查找失败)。
斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
斐波那契查找的时间复杂度还是O(log 2 n ),但是 与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,而除法比加减法要占用更多的时间,因此,斐波那契查找的运行时间理论上比折半查找小,但是还是得视具体情况而定。

四、举例

对于斐波那契数列:1、1、2、3、5、8、13、21、34、55、89……(也可以从0开始),前后两个数字的比值随着数列的增加,越来越接近黄金比值0.618。比如这里的89,把它想象成整个有序表的元素个数,而89是由前面的两个斐波那契数34和55相加之后的和,也就是说把元素个数为89的有序表分成由前55个数据元素组成的前半段和由后34个数据元素组成的后半段,那么前半段元素个数和整个有序表长度的比值就接近黄金比值0.618,假如要查找的元素在前半段,那么继续按照斐波那契数列来看,55 = 34 + 21,所以继续把前半段分成前34个数据元素的前半段和后21个元素的后半段,继续查找,如此反复,直到查找成功或失败,这样就把斐波那契数列应用到查找算法中了。

在这里插入图片描述

从图中可以看出,当有序表的元素个数不是斐波那契数列中的某个数字时,需要把有序表的元素个数长度补齐,让它成为斐波那契数列中的一个数值,当然把原有序表截断肯定是不可能的,不然还怎么查找。然后图中标识每次取斐波那契数列中的某个值时(F[k]),都会进行-1操作,这是因为有序表数组位序从0开始的,纯粹是为了迎合位序从0开始。

五、如何计算

作为折半查找法的加强优化版,它很好地将黄金分割的思想融入到关键字的查找中,它是根据斐波那契序列的特点对有序表进行分割的。

1、斐波那契数组

斐波那契查找,是二分查找的一个变种。其时间复杂度 O(log2n) 。
斐波那契数列,又称黄金分割数列, F{1,1,2,3,5,8,13,21,34,…}F={1,1,2,3,5,8,13,21,34,…} 数学表达式:
在这里插入图片描述
之所以它又称为黄金分割数列,是因为它的前一项与后一项的比值随着数字数量的增多逐渐逼近黄金分割比值0.618。

2、利用斐波那契数组确定元素的位置

所以斐波那契查找改变了二分查找中原有的中值 mid 的求解方式,其 mid 不再代表中值,而是代表了黄金分割点:
在这里插入图片描述
二分查找,以一半元素来分割数组;
斐波那契查找,以黄金分割点来分割数组。
假设表中有 n 个元素,查找过程为取区间中间元素的下标 mid ,对 mid 的关键字与给定值的关键字比较:
(1)如果与给定关键字相同,则查找成功,返回在表中的位置;
(2)如果给定关键字大,向右查找并减小2个斐波那契区间;
(3)如果给定关键字小,向左查找并减小1个斐波那契区间;
(4)重复过程,直到找到关键字(成功)或区间为空集(失败)。

它要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;
开始将k值与第F(k-1)位置的记录进行比较(即mid=low+F(k-1)-1),比较结果也分为三种
(1)key = k[mid], mid位置的元素即为所求;
(2)key>k[mid],low=mid+1,k-=2;
说明:low=mid+1说明待查找的元素在[mid+1,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。
(3)key<k[mid],high=mid-1,k-=1。
说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归 的应用斐波那契查找。

斐波那契搜索也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样的,斐波那契查找也属于一种有序查找算法。

3、举例

举例,假设有集合 e0=2, e1=3, e2=7, e3=14, e4=22, e5=33, e6=55, e7=75, e8=89, e9=123 。
查找元素44的过程:
已知:
元素数量size = 10;
下标区间 [low, high] 为left = 0、right = 9。
则初始化的斐波那契数列为 Fib={1,1,2,3,5,8,13}Fib={1,1,2,3,5,8,13} ,即斐波那契数列最后一位要比size - 1大。
此时查找第一步为:此时刚初始化完,斐波那契数列最后一个区间为第6个区间,即区间(8, 13);第8个数字为当前黄金分割点,则第8个数字下标为下标7,检测的数字为 e7 ;以8分割数组后,左区间为(1, 8)。
在这里插入图片描述
此时查找第二步为:同第一步,黄金分割点为第5个数字下标为4。
在这里插入图片描述
上一步结束,还剩 { 33 55 } ,此时查找第三步为:黄金分割点为第2个数字55,它的下标为6。
在这里插入图片描述
上一步结束,还剩 { 33 } ,此时查找第四步为:黄金分割点为第1个数字33,它的下标为5。

在这里插入图片描述

六、代码实现

1、斐波那契数组实现

//生成斐波那契数列
void  Fibonacci(int* F)
{int i = 0;F[0] = 1;F[1] = 1;for ( i = 2; i < N; ++i){F[i] = F[i - 1] + F[i - 2];}
}

2、斐波那契查找

int search(int* a, int  key, int n)
{int i = 0, low = 0, high = n - 1;int mid = 0, k = 0, F[N];Fibonacci(F);while (n >F[k] - 1)  //计算出N在斐波那契中的数列项{++k;}//当数组不满足时补全数组for ( i = 0; i < F[k]-1; ++i){a[i] = a[high];   //用数组最后一项补全数组}while (low <= high){mid = low + F[k - 1] - 1; //根据斐波那契数列进行分割if (a[mid] > key)   //更小时,在左边{high = mid - 1;k -= 1;   //左边:F[N-1] - 1  总式: F[N] - 1 = F[N-1] - 1 + F[N-2] -1 + 1}else if(a[mid] < key){low = mid + 1; k -= 2;  // 右边:F[N - 12] - 1 }else{if (mid <= high)//如果为真则找到相应位置 return mid;elsereturn -1;}}
}

3、实验数据及测试

#include<stdio.h>
#define N 30//生成斐波那契数列
void  Fibonacci(int* F)
{int i = 0;F[0] = 1;F[1] = 1;for ( i = 2; i < N; ++i){F[i] = F[i - 1] + F[i - 2];}
}
int search(int* a, int  key, int n)
{int i = 0, low = 0, high = n - 1;int mid = 0, k = 0, F[N];Fibonacci(F);while (n >F[k] - 1)  //计算出N在斐波那契中的数列项{++k;}//当数组不满足时补全数组for ( i = 0; i < F[k]-1; ++i){a[i] = a[high];   //用数组最后一项补全数组}while (low <= high){mid = low + F[k - 1] - 1; //根据斐波那契数列进行分割if (a[mid] > key)   //更小时,在左边{high = mid - 1;k -= 1;   //左边:F[N-1] - 1  总式: F[N] - 1 = F[N-1] - 1 + F[N-2] -1 + 1}else if(a[mid] < key){low = mid + 1; k -= 2;  // 右边:F[N - 12] - 1 }else{if (mid <= high)//如果为真则找到相应位置 return mid;elsereturn -1;}}
}
int main()
{int a[N] = { 2,3,5,7,9,11,12,15,19,22 };int k, r = 0;printf("请输入要查找的数字:");scanf_s("%d", &k);r = search(a, k, 10);if (r != -1)printf("\n在数组的第%d个位置找到元素:%d\n", r + 1, k);elseprintf("\n未在数组中找到该元素:%d\n", k);return 0;
}

在这里插入图片描述

4、编译环境

Visual Studio 2019

七、后记

折半查找法https://blog.csdn.net/qq_45768871/article/details/104975755
插值查找(比例查找法)https://blog.csdn.net/qq_45768871/article/details/104975698

这篇关于斐波那契查找(黄金分割查找算法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/275497

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

最大公因数:欧几里得算法

简述         求两个数字 m和n 的最大公因数,假设r是m%n的余数,只要n不等于0,就一直执行 m=n,n=r 举例 以18和12为例 m n r18 % 12 = 612 % 6 = 06 0所以最大公因数为:6 代码实现 #include<iostream>using namespace std;/