算法 费氏搜寻法 Python

费氏搜寻法简介
费氏搜寻法,利用斐波那契数列从有序数列中搜寻特定元素的一种搜索算法。

上文说的是二分法,二分法每次搜寻时,都会将区间分为一半,所以其时间为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复现该算法过程中提供的帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值