【数据结构】斐波那锲查找算法

【数据结构】斐波那锲查找算法


在写斐波那锲查找算法时遇到ArrayIndexOutOfBoundsException错误,错误提示如下图,即出现了k=0,程序查询第k-1个斐波那锲数列的值时出现了索引越界。

【数据结构】斐波那锲查找算法_第1张图片

下面是修改错误后运行正确的斐波那锲查找算法

import java.util.*;

/**
 * @author Calculus
 * @create 2022-04-21 20:22
 */
public class FibonacciSearch {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 39, 39, 39, 100, 100, 100, 1001};
        int[] fibArray = getFib(arr);
        int[] newArr = extendArr(arr, fibArray);
		//修改错误的关键所在!
        fibArray[0] = 0;
        
        Set<Integer> set = search(newArr, arr.length, 0, newArr.length - 1, 0, fibArray, fibArray.length - 1);
        System.out.println(set);
    }

    // 获取斐波那锲数列
    public static int[] getFib(int[] arr) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(1);
        while (true) {
            if (list.get(list.size() - 1) >= arr.length) {
                break;
            }
            list.add(list.get(list.size() - 1) + list.get(list.size() - 2));
        }
        int[] fibArray = list.stream().mapToInt(Integer::intValue).toArray();
        return fibArray;
    }

    // 延长arr数组
    public static int[] extendArr(int[] arr, int[] fibArray) {
        // 延长arr数组
        int[] newArr = Arrays.copyOf(arr, fibArray[fibArray.length - 1]);
        if (arr.length < newArr.length) {
            for (int i = arr.length; i < newArr.length; i++) {
                newArr[i] = arr[arr.length - 1];
            }
        }
        return newArr;
    }

    // 查找
    public static Set<Integer> search(int[] newArr, int arrLength, int left, int right, int targetValue, int[] fibArray, int k) {
        if (left > right) {
            return new HashSet<Integer>();
        }
        // 取mid数值
        int mid = left + fibArray[k - 1] ;
        // 寻找
        if (newArr[mid] < targetValue) {
            k -= 2;
            return search(newArr, arrLength, mid + 1, right, targetValue, fibArray, k);
        } else if (newArr[mid] > targetValue) {
            k -= 1;
            return search(newArr, arrLength, left, mid - 1, targetValue, fibArray, k);
        } else {
            Set<Integer> set = new HashSet<>();

            if (mid > arrLength - 1) {
                set.add(arrLength - 1);
            } else {
                set.add(mid);
            }

            int temp = mid - 1;
            while (temp >= 0 && newArr[temp] == newArr[mid]) {
                if (temp > arrLength - 1) {
                    set.add(arrLength - 1);
                } else {
                    set.add(temp);
                }
                temp--;
            }

            temp = mid + 1;
            while (temp < newArr.length && newArr[temp] == newArr[mid]) {
                if (temp > arrLength - 1) {
                    set.add(arrLength - 1);
                } else {
                    set.add(temp);
                }
                temp++;
            }
            return set;
        }


    }

}



原因分析:

当在查询比数组中最小的数值还要小的数值时,程序会进入到下面这一步:
left=0,right=0,k=1;
而根据mid的计算公式:int mid = left + fibArray[k - 1]; 可得出此时mid=1;
此时左指针left和右指针right均为0,而我们计算得到的中间指针mid却为1,这是不合理的!
而这种不合理性正是由于斐波那锲数列的第一个数字为1所导致的:
从划分的角度来看:当k=1时,此时,fibArray[k]=1,这表示我们已经无法再去划分数组了,而此时fibArray[k-1]=1意味着我们还可以把长度为1的数组划分,这就造成了错误的出现!


解决方案:

方法1.在递归查询之前将斐波那契额数组的第1个元素位置置0: fibArray[0] = 0;
方法2:int mid = left + fibArray[k - 1]
以上两种方法都是为了避免出现left=0,right=0,而mid=1的情况出现

你可能感兴趣的:(java,数据结构)