斐波那契查找 java代码实现(包含普通和递归两种)

package com.itheima.security.springboot.algorithm.search;

import java.util.Arrays;

/**
 * @description:
 * @Author: muyi
 * @CreateDate: 2020/12/2 12:00
 */
public class FibonacciSearch {

    /**
     * 斐波那契数组的长度
     */
    private final static int FIB_ARRAY_LENGTH = 10;
    /**
     * 斐波那契数组的最小长度
     */
    private final static int FIB_ARRAY_MIN_LENGTH = 3;

    public static void main(String[] args) {
        System.out.println(Arrays.toString(getFibArray()));
        int[] array = {1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88, 88, 88, 88, 88};
        System.out.println(array.length);
        System.out.println(fibonacciSearch(array, 47));
        System.out.println(recurseFibonacciSearch(array, getFibArray(), 47, 0, array.length - 1, 7));

    }

    /**
     * 获取斐波那契数组
     *
     * @Author muyi
     * @Date 12:07 2020/12/2
     */
    private static int[] getFibArray() {
        int[] fibArray = new int[FIB_ARRAY_LENGTH];
        if (FIB_ARRAY_LENGTH < FIB_ARRAY_MIN_LENGTH) {
            throw new IllegalArgumentException("斐波那契数列的最小长度为3");
        }
        fibArray[0] = 1;
        fibArray[1] = 1;
        for (int i = 2; i < FIB_ARRAY_LENGTH; i++) {
            fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
        }
        return fibArray;
    }

    /**
     * 斐波那契查找(非递归)
     *
     * @param array 待查找的数组
     * @param key   查找的关键字
     * @return int 关键字在数组的位置,未查找到,返回-1
     * @Author muyi
     * @Date 12:08 2020/12/2
     */
    public static int fibonacciSearch(int[] array, int key) {
        if (array == null || array.length == 0) {
            return -1;
        }
        int length = array.length;
        // 制造一个长度为10的斐波数列,要特别明确:这里面的数据是索引值!!!!
        int[] fb = getFibArray();
        int k = 0;
        // 找出数组的长度在斐波数列(减1)中的位置,将决定如何拆分!
        while (length > fb[k] - 1) {
            // 此时K的值为斐波那契数列中大于【数组长度的最小值】所在的索引值
            k++;
        }
        // 构造一个长度为fb[k] - 1的新数列,构造查询的中间数组
        int[] temp = Arrays.copyOf(array, fb[k]);
        // 获取数组最后一个位置的元素值,用该值对新数列length以后的元素进行填充
        int arrayLastValue = array[length - 1];
        for (int i = length; i < temp.length; i++) {
            temp[i] = arrayLastValue;
        }

        // 刚开始是在整个中间数组中进行茶渣,即对查询数组进行黄金分割
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            /**
             * 从 temp 数组中找黄金分割点,
             * 黄金分隔点即是斐波那契数组的前一索引位置的数字
             * 斐波那契的特点:f[k] = f[k-1] + f[k-2] ===》 f[k]-1 = f[k-1]-1 + f[k-2]-1 +1
             * 黄金分割点的值为 f[k-1] -1,正常黄金分割点的值应该是f[k-1],但这里代表的是数组的索引,从0开始,故这里需要对其进行-1操作
             *                         low是作为获取黄金分隔点的基准值
             */
            int middle = low + fb[k - 1] - 1;
            // 如果黄金分隔点的数大于关键字,那继续从黄金分割点之前查找
            if (temp[middle] > key) {
                high = middle - 1;
                // 前面的元素个数是 f[k-1] 个
                k--;
            }
            // 如果小于关键字,那继续从黄金分割点之后查找
            else if (temp[middle] < key) {
                low = middle + 1;
                // 后面的元素个数是 f[k-2] 个
                k -= 2;
            } else {
                // 若相等则说明mid即为查找到的位置
                if (middle <= high) {
                    return middle;
                }
                // middle的值已经大于high,进入扩展数组的填充部分,即最后一个数就是要查找的数。
                else {
                    return high;
                }
            }
        }
        return -1;
    }

    /**
     * 斐波那契查找(递归方式)
     *
     * @param array    待查找的数组
     * @param fibArray 斐波那契数组
     * @param key      关键字
     * @param low      低索引值
     * @param high     高索引值
     * @param index    索引值,即查找数组最大长度所对应的斐波那契数组中数据的索引值
     * @return int 关键字在数组的位置,未查找到,返回-1
     * @Author muyi
     * @Date 14:32 2020/12/2
     */
    public static int recurseFibonacciSearch(int[] array, int[] fibArray, int key, int low, int high, int index) {
        /**
         *  key < array[low]:小于最小值
         *  key > array[high]:大于最大值
         *  low > high:遍历整个数组均未找到元素,退出
         */
        if (array == null || array.length == 0 || key < array[low] || key > array[high] || low > high) {
            return -1;
        }
        int middle = low + fibArray[index - 1] - 1;
        if (key < array[middle]) {
            // 如果小于关键字,在黄金分隔点之前查找
            return recurseFibonacciSearch(array, fibArray, key, low, middle - 1, index - 1);
        } else if (key > array[middle]) {
            // 如果大于关键字,在黄金分割点之后查找
            return recurseFibonacciSearch(array, fibArray, key, middle + 1, high, index - 2);
        } else {
            // 若相等则说明 middle 即为查找到的位置
            if (middle <= high) {
                return middle;
                // middle的值已经大于high,进入扩展数组的填充部分,即最后一个数就是要查找的数。
            } else {
                return high;
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值