引言
\quad \quad 在介绍斐波那契查找算法之前,先介绍一下很它紧密相连的一个概念——黄金分割。黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。因此被称为黄金分割。斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)。然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。
\quad \quad
相对于折半查找,一般将待比较的key值与第mid=(low+high)/2位置的元素比较,比较结果分三种情况:
(1)key值与第mid=(low+high)/2相等,mid位置的元素即为所求;
(2)key值大于第mid=(low+high)/2,则令 low=mid+1;
(3)key值小于第mid=(low+high)/2,则令high=mid-1。
\quad \quad
斐波那契搜索也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。
1、概述
\quad \quad 斐波那契查找,又称斐波那契搜索,是区间中单峰函数的搜索技术。
\quad \quad 斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。
2、原理
\quad \quad 斐波那契查找法与折半查找的基本思想类似,都是减少查找序列的长度,分而治之地进行关键字的查找。他的查找过程是:先确定待查找记录的所在的范围,然后逐渐缩小查找的范围,直至找到该记录为止(也可能查找失败)。
算法过程
1、首先定义斐波那契数列,找出合适的F(k),计算初始查找点
- 在斐波那契数列找一个略等于大于查找表中元素个数的数F[k];
- 根据1中长度创建该长度的裴波那契数组,再通过F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)生成裴波那契数列为数组赋值
- 将原查找表扩展为长度为(F[k]-1) (如果要补充元素,则补充重复最后一个元素,直到满足(F[k]-1)个元素);
- 完成后进行斐波那契分割,即 F[k] 个元素分割为前半部分 F[k-1] 个元素,后半部分 F[k-2] 个元素,分隔点mid=low+F(k-1)-1),找出要查找的元素在那一部分并递归,直到找到。
2、进行比较,并更新查找点即更新k
比较结果也分为三种:key:待查关键值,k为待查列表
- (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个,所以可以递归 的应用斐波那契查找。
对 mid= low +F(k-1)-1的解释:
3、算法
【python代码实现】
def FibonacciSearch(data,key):
length=len(data)
k = 1;
low = 0
high = length-1
if(key < data[low] or key>data[high]): #索引超出范围返回错误
print("Error!!! The ", key, " is not in the data!!!")
return -1
data = list(data)
F=[0,1]
while F[k] < length: #生成斐波那契数列
F.append(F[k-1] + F[k])
k += 1
low = F[0]
high = F[k]-1
while length < F[k]-1: #将数据个数补全
data.append(data[length-1])
length = length + 1
data = array(data)
while(low<=high):
mid = low+F[k-1]-1 #计算当前分割下标
if(data[mid] > key): #若查找记录小于当前分割记录
high = mid-1 #调整分割记录
k -= 1
elif(data[mid] < key): #若查找记录大于当前分割记录
low = mid+1
k -= 2
else: #若查找记录等于当前分割记录
return mid
if(data[mid] != key): #数据key不在查询列表data中返回错误
print("Error!!! The ", key, " is not in the data!!!")
return -1
if __name__ == '__main__':
data = array([0,1,16,24,35,48,59,62,73,88,99])
key = 0
idx = FibonacciSearch(data, key)
print(data)
print("The ", key, " is the ", idx, "th value of the data.")
4、特点
时间复杂度: O ( l o g 2 n ) O(log_2n) O(log2n)
\quad \quad 如果要查找的记录在右侧,则左边的数据都不用在哦按段了,不断反复进行下去,对处于当中的大部分数据源,其工作效率要高一些所以尽管斐波那契查找的时间复杂度也为 O ( l o g 2 n ) O(log_2n) O(log2n)。但平均性能上来说,斐波那契查找要优于折半查找,可惜如果是最坏情况,比如这里key=1的时候,那么始终都处于左侧长半区在查找,则查找效率要低于折半查找。