斐波那契查找算法实现(Java)

斐波那契查找算法

斐波那契查找算法思想介绍

斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n](如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。

斐波那契查找算法原理分析

斐波那契查找算法与二分法查找基本类似。不同的是二分法查找是折半查找,而斐波那契查找算法利用斐波那契数列的黄金分割特性,利用黄金分割点查找。即mid = left + f(k-1) - 1(f代表斐波那契数列)。

图解

  • 由斐波那契数列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 = left + f(k-1) - 1。
  • 每个字段也可以像上面一样划分
  • 顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。

代码实现

package com.athome.search;

import java.util.Arrays;

/**
 * Description:
 * Author:江洋大盗
 * Date:2021/1/21 19:58
 */
public class FibonacciSearch {
    
    
    public static void main(String[] args) {
    
    
        //测试黄金分割法查找
        int[] arr = {
    
    1, 5, 15, 19, 25, 32, 34, 48, 56, 89};
        int i = fibSearch(arr, 15);
        System.out.println("黄金分割法查找:" + i);

    }

    /**
     * 非递归求斐波那契数列
     *
     * @param maxSize 斐波那契数列的长度
     * @return 返回斐波那契数列
     */
    public static int[] fib(int maxSize) {
    
    
        int[] fib = new int[maxSize];
        fib[0] = fib[1] = 1;
        for (int i = 2; i < maxSize; i++) {
    
    
            fib[i] = fib[i - 1] + fib[i - 2];
        }
        return fib;
    }

    /**
     * @param arr    待查找数据的数组
     * @param target 目标值
     * @return 返回查询结果的角标,若查询不到返回-1
     */
    public static int fibSearch(int[] arr, int target) {
    
    
        int left = 0;//左角标
        int right = arr.length - 1;//右角标
        //1.首先获取一个斐波那契数列,此处以20为例,如有需求可以更换其他值。
        int[] fib = fib(20);
        //2.如果arr不够长需要补足长度
        int k = 0;//记录合适的数组长度
        while (right > fib[k] - 1) {
    
    
            k++;
        }
        //3.创建临世数组,以fib[k]为长度。
        int[] temp = Arrays.copyOf(arr, fib[k]);
        //4.数组中的空元素用最后一个元素补齐
        for (int i = right + 1; i < temp.length; i++) {
    
    
            temp[i] = arr[right];
        }
        int mid;//记录黄金分割点
        while (left <= right) {
    
    
            mid = left + fib[k] - 1;
            if (target < temp[mid]) {
    
    
                right = mid - 1;
                k -= 1;//换到前半段的黄金分割点
                //推导:全部元素 = 前面元素 + 后面元素
                //     f(k)   = f(k-1) + f(k-2)
                //可见前半段元素为 f(k-1)
                //换到前半段就是: f(k-1)
            } else if (target > temp[mid]) {
    
    
                left = mid + 1;
                k -= 2;//换到后半段的黄金分割点,推导同上面一样。
            } else {
    
    
                return Math.min(mid, right);//有可能找到的值是后来填充进去的。
            }
        }
        return -1;
    }
}

结语

只要能收获甜蜜,荆棘丛中也有蜜蜂忙碌的身影,未来的你一定会感谢现在努力的自己。

猜你喜欢

转载自blog.csdn.net/m0_52099927/article/details/112972242