斐波那契查找及其相关实例代码

本文介绍了斐波那契查找算法,利用黄金分割原理对有序数组进行查找,与折半查找和插值查找相比,具有特定场景下的优势,尤其在海量数据中,其简单加减运算可能提高效率。
摘要由CSDN通过智能技术生成

折半查找是从中间分,也就是说,每一次查找总是一分为二,无论数据偏大还是偏小,很多时候这都未必就是最合理的做法。除了插值查找,我们再介绍一种有序查找,斐波那契查找(Fibonacci Search),它是利用了黄金分割原理来实现的。
斐波那契数列我们在前面4.8节讲递归时,也详细地介绍了它。如何利用这个数列来作为分割呢?
为了能够介绍清楚这个查找算法,我们先需要有一个斐波那契数列的数组。
下面我们根据代码来看程序是如何运行的:

/*  斐波那契查找  */
int  Fibonacci_Search(int  *a,  int  n,  int  key)
{
int  low,  high,  mid,  i,  k;
/*定义最低下标为记录首位  */
low  =  1;              
/*定义最高下标为记录末位  */
high  =  n;             
k  =  0;
/*  计算n位于斐波那契数列的位置  */
while  (n  >  F[k]  -  1)                       
k++;
/*  将不满的数值补全  */
for  (i  =  n;  i  <  F[k]  -  1;  i++)        
a[i]  =  a[n];
while  (low  <=  high)
{
/*  计算当前分隔的下标  */
mid  =  low  +  F[k  -  1]  -  1;          
/*  若查找记录小于当前分隔记录  */
if  (key  <  a[mid])    
{/*  最高下标调整到分隔下标mid-1处  */
high  =  mid  -  1;     
/*  斐波那契数列下标减一位  */
k  =  k  -  1;          }
/*  若查找记录大于当前分隔记录  */
else  if  (key  >  a[mid])                
{/*  最低下标调整到分隔下标mid+1处  */
low  =  mid  +  1;      
/*  斐波那契数列下标减两位  */
k  =  k  -  2;          
}else
{
if  (mid  <=  n)
/*  若相等则说明mid即为查找到的位置  */
return  mid;            
else
/*  若mid>n说明是补全数值,返回n  */
return  n;              
}
}
return  0;
}

下面对代码进行详细解释说明:

  1. 首先定义了函数Fibonacci_Search,输入参数为一个整型数组a,数组长度为n,要查找的关键字为key

  2. 定义了变量lowhigh分别表示最低下标和最高下标,初始值分别为数组的第一个和最后一个元素的下标。

  3. 定义了变量k为0,用于计算关键字所在的斐波那契数列位置。

  4. 计算关键字所在的斐波那契数列位置。通过循环找到满足n > F[k] - 1的最小k值。

  5. 将数组的长度扩展到满足斐波那契数列的要求。通过循环将数组的最后一个元素复制到扩展后的位置。

  6. 进入查找过程的主循环,当low小于等于high时循环执行。

  7. 计算当前分隔的下标mid,通过low + F[k - 1] - 1计算得到。

  8. 如果关键字小于当前分隔记录,说明关键字在分隔的左侧,将high调整到mid - 1处,同时将k减1。

  9. 如果关键字大于当前分隔记录,说明关键字在分隔的右侧,将low调整到mid + 1处,同时将k减2。

  10. 如果关键字等于当前分隔记录,分两种情况处理: a. 如果mid小于等于n,说明mid即为查找到的位置,返回mid。 b. 如果mid大于n,说明扩展的位置是补全的数值,返回n

  11. 如果循环结束时仍未找到关键字,返回0。

综上所述,该代码实现了使用斐波那契数列进行查找的算法,通过将数组长度扩展到满足斐波那契数列的要求,并以斐波那契数列的划分进行二分查找的方式,提高了查找效率。


斐波那契查找算法的核心在于:

  • 1)当key=a[mid]时,查找就成功;
  • 2)当key<a[mid]时,新范围是第low个到第mid-1个,此时范围个数为F[k-1]-1个;
  • 3)当key>a[mid]时,新范围是第m+1个到第high个,此时范围个数为F[k-2]-1个。


也就是说,如果要查找的记录在右侧,则左侧的数据都不用再判断了,不断反复进行下去,对处于当中的大部分数据,其工作效率要高一些。所以尽管斐波那契查找的时间复杂也为O(logn),但就平均性能来说,斐波那契查找要优于折半查找。可惜如果是最坏情况,比如这里key=1,那么始终都处于左侧长半区在查找,则查找效率要低于折半查找。


还有比较关键的一点,折半查找是进行加法与除法运算(mid=(low+high)/2),插值查找进行复杂的四则运算(mid=low+(high-low)*(key-a[low])/(a[high]-a[low])),而斐波那契查找只是最简单加减法运算(mid=low+F[k-1]-1),在海量数据的查找过程中,这种细微的差别可能会影响最终的查找效率。
应该说,三种有序表的查找本质上是分隔点的选择不同,各有优劣,实际开发时可根据数据的特点综合考虑再做出选择。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值