二分查找、插值查找、斐波那契查找

对于一个有序的数列,查找数列中是否有某个数值并返回其下标。
1、二分查找

    public static int binarySearch(int[] arr,int findValue) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) >>> 1;  //防止两个int相加超出int的最大值
            if (arr[mid] > findValue) {
                right = mid - 1;
            } else if (arr[mid] < findValue) {
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

2、插值查找
相对于二分查找,我们将计算mid的公式优化,将findValue带入进去。

    public static int insertValueSearch(int[] arr,int left,int right,int findValue) {
        //findValue<arr[0]和findValue>arr[arr.length-1]这两个条件必须要,否则计算出的mid值可能造成数组下标越界
        if (left > right || findValue < arr[0] || findValue > arr[arr.length - 1]) {
            return -1;
        }
        int mid = left + (right - left) * (findValue - arr[left]) / (arr[right] - arr[left]);  //优化了计算mid的公式
        if (arr[mid] > findValue) {
            return insertValueSearch(arr, left, mid - 1, findValue);
        } else if (arr[mid] < findValue) {
            return insertValueSearch(arr, mid + 1, right, findValue);
        } else {
            return mid;
        }
    }

3、斐波那契查找
斐波那契数列:第n项等于n-1与n-2项的和,如[1,1,2,3,5,8,13]

    /**  使用非递归方法获取斐波那契数列,因为mid=low+f(k-1)-1
     * @return  斐波那契数列
     */
    public static int[] fib() {
    	int maxSize = 20;
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i - 2] + f[i - 1];
        }
        return f;
    }
        /** 编写斐波那契查找算法
     * @param a   数组
     * @param key 我们要查找的值
     * @return 下标,没有返回-1
     */
    public static int fibSearch(int[] a,int key) {
        int low = 0;
        int high = a.length - 1;
        int k = 0; //表示斐波那契分割数值的下标
        int mid;
        int f[] = fib();
        //获取斐波那契分割数值的下标
        while (high > f[k] - 1) {
            k++;
        }
        //因为f[k]的值可能大于a的长度,因此我们构造一个新的数组,并指向a
        int[] temp = Arrays.copyOf(a, f[k]);
        //将a数组最后一个元素填充到多出来的下标里
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = a[high];
        }
        while (low <= high) {
            mid = low + f[k - 1] - 1;
            if (key < temp[mid]) {   //向左
                high = mid - 1;
                k--;
                //k--的说明:f[k]=f[k-1]+f[k-2],即在f[k-1]的前面查找k--,即下次循环mid=f[k-1-1]-1
            } else if (key > temp[mid]) {
                low = mid + 1;
                k -= 2;
                //k-=2的说明:因为后面我们有f[k-2],即在f[k-2]的前面进行查找,即下次循环mid=f[k-1-2]-1
            } else {
                //需要确定返回的是哪个下标
                if (mid <= high) {
                    return mid;
                } else {
                    return high;
                }
            }
        }
        return -1;
    }

插值查找是对二分查找的一个优化,对于数据量比较大,关键字分布比较均匀的数据来说,速度较快;关键字分布不均匀的情况下,该方法不一定比二分查找要好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值