费氏搜寻法简介
费氏搜寻法,利用斐波那契数列从有序数列中搜寻特定元素的一种搜索算法。
上文说的是二分法,二分法每次搜寻时,都会将区间分为一半,所以其时间为O(log₂n)。费氏搜寻,其利用费氏数列作为间隔来搜寻下一个数,所以区间收敛的速度更快,搜寻时间为O(logn)。
用一个例子来说明:
查询的数组:num[]
0 0 1 1 1 2 2 2 3 5 6 7 8 8 9
斐波拉契数列:F[]
1 1 2 3 5 8 13 21…
现在假定我们查询的数字是:find=7.
方便计算,我们的num[]和F[]的数组下标都从1开始。
首先,可以知道数组num长度n=15,先找到(尽可能大的)小于等于15的F[x]=13,他的下标x=7,此时还需要一个公式:F[x]+m=n,所以m=15-13=2;
x,m,F[x]在一开始数组长度知道的情况下就可以知道了。
第一次搜索:
不是从x=7,开始查询的,而是x–,i=x=6开始查询的,如果num[6]<7,这时候,i+=m,第二次搜索的时候就从第8个开始。(如果num[6]>7,则i是i-=F[x])
i=6 num[6]=2<7 i+=2
第二次搜索:
第二次搜索就从上一次 得出的i=8开始搜索,这时候,num[8]=2<7,这时候i的变化不再是加减m了,而是加减斐波拉契数列的值(F[x])了。num[i]小于我们要查找的数值,i就加斐波拉契数列的值,反之则减.
i=8 num[8]=2<7 i+=F[–x] 即i+=F[5] i=8+5=13
第三次搜索
i=13 num[13]=8>7 i-=F[–x] 即i-=F[4] i=13-3=10
第四次搜索:
i=10 num[10]=5<7 i+=F[–x] 即i+=F[3] i=10+2=12
第五次搜索:
i=12 num[12]=7 这样就找到我们要查找的数值7,他是索引12.
总结:
费氏搜寻会先透过公式计算求出第一个要搜寻数的位置,F[x]+m=n,计算出F[x],m,x的值,用费氏数列作为间隔来搜寻下一个数,区间收敛的速度更快,同时本身只会用到加减法,在运算上也可以加快。
接下来上Python代码
import datetime
# 开始时间
start = datetime.datetime.now()
number = [i for i in range(0, 200, 3)] # 随机数列
print("随机数列:", len(number), number) # [0, 3, 6, 9, 12, 15, 18]
find = 39 # 目标搜寻 18
MAX = len(number)
def fib_loop(n):
a, b = 0, 1
while n > 0:
a, b = b, a + b
n -= 1
return a
Fib = [fib_loop(i) for i in range(MAX)] # 创建斐波那契数列
print("生成的斐波那契数列:", len(Fib), Fib)
def findx(n): # 找X的值
i = 0
while Fib[i] <= n:
i += 1
i -= 1
return i # 找到第i个Fib元素小于等于MAX+1
def fibsearch(number, find, Fib):
x = findx(find + 1) # 斐波那契数列中第x个数刚好不大于find + 1。find是确定的,所以比较的起始点是确定的。
m = MAX - Fib[x] # 得到一个较小的差值。m的值也是确定的。
print(f"x = {x}, m = {m}, Fib[x] = {Fib[x]}")
x -= 1
i = x
if number[i] < find: # i的初值也是确定的。
i += m
while Fib[x] > 0: # 搜寻,x值不断减小,范围越来越小,搜寻越来越精细
if number[i] < find: # 小于被搜寻的值
i += Fib[x - 1] # 右移搜寻位置
x -= 1
elif number[i] > find: # 大于被搜寻值
i -= Fib[x - 1] # 左移搜寻位置
x -= 1
else:
return i # 相等,找到
return -1 # 搜寻步子已经最小,还是没找到,搜寻结束
c = fibsearch(number, find, Fib)
print("fibsearch 函数的返回值:", c)
# 结束时间
end = datetime.datetime.now()
# 输出
print("final is in ", end - start)
当你看到本篇文章时,默认你已经掌握了Python语法相关知识。
你可以修改随机数列,查看搜索返回的索引,验证算法是否正确。
如果有什么疑问,欢迎加Q群一起1121306638前来探讨。
本文参考了https://blog.csdn.net/qq_41097354/article/details/90341132
感谢某大佬在使用Python复现该算法过程中提供的帮助。