java实现简单的二分查找,插值查找

前情提要:二分查找也叫折半查找,即在一个有序数组中通过每次将寻找的范围折半的方式来查找数据

解析即在代码里:


/**
 * @author hongda
 * 2020-04-09-17
 * <p>
 * 使用二分查找的前提是该数组是有序的
 */


public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1234};
//        int i = binarySearch(arr, 0, arr.length - 1, 89);
//        System.out.println("index=" + i)
        ArrayList<Integer> list = binarySearch2(arr, 0, arr.length - 1, 1000);
        System.out.println("resIndexList" + list);

    }


    /**
     * @param arr     数组
     * @param left    左边的索引
     * @param right   右边的索引
     * @param findVal 要查找的值
     * @return 如果找到就返回下标, 没有找到就返回-1
     */
    public static int binarySearch(int[] arr, int left, int right, int findVal) {
        //设立一个中间值,这个值在二分查找里就是数组的中间
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        //当left>right时,说明递归了整个数组,但是没有找到
        if (left > right) {
            return -1;
        }
        //既然中间的这个数已经是不等于midVal了,那么把它抛弃也无可厚非
        //所有下面的边界分别是mid+1和mid-1
        if (findVal > midVal) {
            return binarySearch(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return binarySearch(arr, left, mid - 1, findVal);
        }
        //当找到这个值的时候,就返回其所在的下标
        else {
            return mid;
        }

    }

    /**
     * 当一个有序数组中,有多个相同的数值时,如何将所有的数值都查找到
     * 1.在找到mid值时,不要马上返回
     * 2.向mid索引值的左边扫描,将所有满足值的下标加入到集合ArrayList中
     * 3.向mid索引值的右边扫描,将所有满足值的下标加入到集合ArrayList中
     */
    public static ArrayList<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        //当left>right时,说明递归了整个数组,但是没有找到
        if (left > right) {
            return new ArrayList<Integer>();
        }
        if (findVal > midVal) {
            return binarySearch2(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return binarySearch2(arr, left, mid - 1, findVal);
        } else {
            ArrayList<Integer> resIndexList = new ArrayList<>();
            //向左查找
            int temp = mid - 1;
            while (true) {
                if (temp < 0 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp);
                temp -= 1;
            }
            resIndexList.add(mid);
            //向右查找
            temp = mid + 1;
            while (true) {
                if (temp > arr.length - 1 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp);
                temp += 1;
            }
            return resIndexList;
        }

    }
}

插值查找:对二分查找的一种改进式算法,通过公式计算出尽可能接近的中间值,而非折半查找那样死板,从而减少递归的次数

解析附在代码中:

  /**
     * @param arr     数组
     * @param left    左边的索引
     * @param right   右边的索引
     * @param findVal 要查找的值
     * @return 如果找到就返回下标, 没有找到就返回-1
     */
    public static int insertValueSearch(int[] arr, int left, int right, int findVal) {
        //注意后面的条件必须存在,否则我们得到的mid可能越界,因为后面计算的中间值是有公式的
        if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
            return -1;
        }
        //插值算法公式
        int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
        int midVal = arr[mid];
        //下面的就和二分查找法思维一致
        if (findVal > midVal) {
            return insertValueSearch(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return insertValueSearch(arr, left, mid - 1, findVal);

        }else {
            return mid;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值