数据结构小白之斐波那契查找

1.斐波那契数列的简单介绍(摘自百度)

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

2.斐波那契数列和斐波那契查找算法之间的关系

前面我们谈过了二分查找算法和插值查找算法,也说过了二分查找算法和插值算法中存在着很多相似的地方,唯一不同的地方就是它们对于mid的定位不同,二分查找算法(mid=(low+high)/2), 插值算法(mid=low+(key-arr[low])/(high-low)

对于斐波那契查找算法而言,实现的方式和上述代码类似,唯一不同的也是对于mid的定位方式,在这里使用的是基于斐波那契数列的方式对mid进行定位

mid=low+F(k-1)-1 F表示斐波那契数列

3.如何推导公式

首先可以知道斐波那契数列公式如下: F(k)=F(k-1)+F(k-2),所以可以对上述公式进行一些改造 F(k)-1=F(k-1)-1+F(k-2)-1+1

因此可以得到如下图所示的结构,将整个数列F(k)-1 ,分成F(k-1)-1和F[k-2]-1两个部分,中间通过mid进行分割

所以可以得到mid的值为 low+F[k-1]-1

注:相当于把左段向后平移low个单位得到mid

4.斐波那契查找算法思路一览

(1)准备斐波那契数列

public static int[] fib() {
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }

(2) 在编写具体的算法之前,需要进行原搜索数组和斐波那契数组的适应工作

*F(k)-1的值要大于等于原数组的长度

 //将顺序表的长度和斐波那契数列进行自适应
        while (high > f[k] - 1) {
            k++;
        }

*修改之后将原数组进行拓展,将原数组的长度和斐波那契数列的值进行匹配

   //因为f[K]可能大于数组的长度,因此需要使用Arrays构造一个新的数组,并指向a[],不足的部分会使用0去填充
        int[] temp = Arrays.copyOf(a, f[k]);
        
        //temp={1,8,10,89,1000,1234,0,0,0}->{1,8,10,89,1000,1234,1234,1234}
        //新构建的数组用最后数进行填充
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = a[high];
        }

注: 在这次变化之后 原顺序数组变成了{1,8,10,89,1000,1234,1234,1234} 斐波那契数列变成了 f[6]={1,1,2,3,5,8}

已经做到了 7(high)<=f[6]-1  arr[f[6]]={1,8,10,89,1000,1234,1234,1234}

(3) 开始喜闻乐见的查找(这次咱们玩玩非递归的方式)

 while (low <= high) {
            //借助斐波那契数列对mid进行定位
            mid = low + f[k - 1] - 1;
            if (key < temp[mid]) {//向左查找
                high = mid - 1;
                /**
                 * 全部元素 = 前面元素+后面元素
                 * f[k]=f[k-1]+f[k-2]
                 * 前面有f[k-1]个元素可以继续进行拆分
                 * 本次循环条件mid = low+f[k-1]-1
                 * 下次循环条件mid= low+f[k-1-1]-1
                 * */
                k--;
            } else if (key > temp[mid]) {
                low = mid + 1;
                //下次循环为 mid= f[k-1-2]-1
                k -= 2; //!!! 注意这里不是K+=1 而是k-=2
            } else {
                if (mid <= high) {
                    return mid;
                } else {
                    return high;
                }
            }
        }

(4) 主函数

 public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1234};
        System.out.println(fibSearch(arr, 1000));
    }

(5) 结果

完整代码:https://github.com/Lzin/search_algor/tree/master/src/com/liz/fibonacci_search

发布了193 篇原创文章 · 获赞 70 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/Lzinner/article/details/103070140
今日推荐