数组查找

大纲

  1. 二分查找
  2. 插值查找
  3. 斐波那契查找

tips:数组查找的前提是数组有序

一、二分查找

  /**
     * 找到中间位置,然后递归前后两个部分
     */
    private static int binarySearch(int[] arr,int target,int begin,int end){
        if (end>=begin) {
            int mid = (begin+end)/2;
            if (arr[mid]>target) {
                return binarySearch(arr,target,0,mid-1);
            }else if(arr[mid]<target){
                return binarySearch(arr,target,mid+1,end);
            }else{
                return mid;
            }
        }
        return -1;
    }

二、插值查找

    /**
     * 中值有一定自适应性,适用于数值分布均匀的数组,比如等差数列
     */
    private static int insertSearch(int[] arr,int target,int begin,int end){
        if (end>=begin && target<=arr[end] && target>=arr[begin]) {
            int mid = begin+(end-begin)*(target-arr[begin])/(arr[end]-arr[begin]);
            if (arr[mid]>target) {
                return binarySearch(arr,target,0,mid-1);
            }else if(arr[mid]<target){
                return binarySearch(arr,target,mid+1,end);
            }else{
                return mid;
            }
        }
        return -1;
    }

三、斐波那契查找

    /**
     * 不用2分查找而是根据黄金分割点查找
     */
    private static int fibSearch(int[] arr,int target){
        int[] fib = getFib();//获取一个斐波那契数列
        int fibIndex = 0;
        while (fib[fibIndex] < arr.length) {
            fibIndex++;
        }
        //创建一个新数组,将原来的arr移动到新的数组中,新数组长度为斐波那契数列中的数,长度原来的长度的部分用原数组中最大的补齐
        int[] temp = new int[fib[fibIndex]];
        for (int i = 0; i < fib[fibIndex]; i++) {
            if (i>arr.length-1) {
                temp[i] = arr[arr.length-1];
            }else{
                temp[i] = arr[i];
            }
        }
        //查找
        int left = 0;
        int right = arr.length-1;
        while (right>=left) {
            //斐波那契数列F[K] = F[K-1] + F[K-2]
            //因此在前半段(较长的一段)中,再次分割点就是F[K-1],因后半段(较短的一段)中,再次分割点就是F[K-2]
            //建议自己画图,比较好理解
            int mid = left+fib[fibIndex-1]-1;
            if (temp[mid]>target) {
                right = mid-1;
                fibIndex-=1;
            }else if(temp[mid]<target){
                left = mid+1;
                fibIndex-=2;
            }else {
                //每次查找都在后半部分,mid是有可能计算出来>right的(right一直是arr的最后一个元素指针)
                //出现这种情况返回right即可,right因为后面都是arr[arr.length-1]的值
                if (mid>right) {
                    return right;
                }else{
                    return mid;
                }
            }
        }
        return -1;
    }
    
    public static int[] getFib(){
        int[] fib = new int[20];
        fib[0] = 1;
        fib[1] = 1;
        for (int i = 2; i < fib.length; i++) {
            fib[i] = fib[i-1]+fib[i-2];
        }
        return fib;
    }
原文地址:https://www.cnblogs.com/liuboyuan/p/14651101.html