查找算法

查找算法 [前提有序数组]
思路: 不同的方式去获得 mid 值


二分查找:

  1. 根据 left 左边界、right 右边界,(left + right) / 2 求出中间下标 mid 以及 中间值 midValue
  2. 在 left <= right 的条件下,查找值 findValue 与 中间值midValue 比较。
    2.1 findValue > midValue : 查找值大于中间值,将左边界更新为 mid + 1
    2.2 findValue < midValue :查找值小于中间值,将右边界更新为 mid - 1
    2.3 返回 递归结果
  3. 判断结束条件: left > right 结束

插值查找

  1. 结束判断条件: left > right || findValue < arr[0] || findValue > arr[arrl.length - 1]
    1.1 三个条件缺一不可: 因为插值查找的 mid 计算需要使用到 findValue,如果这里不判断,当 findValue 非常大的时候,比如 90000, 那么计算出来的 mid 值就会非常的大,可能会出现 arr 越界
  2. mid 计算: mid = left + (right - left) * (findValue - arr[left]) / (arr[right] - arr[left])
    2.1 可以理解成 比例去记
    2.2 计算出 中间值 midValue
  3. 在 left <= right 的条件下,判断 findValue 与 midValue 的大小
    3.1 findValue > midValue : 将左边界更新 mid + 1
    3.2 findValue < midValue : 将右边界更新 mid - 1
    3.3 返回 递归结果

斐波那契查找(黄金分割点法查找)

  1. 需要一个斐波那契数列 , maxSize = 20
  2. 定义需要使用到的变量:
    2.1 left = 0 左边界
    2.2 right = arr.length - 1 右边界
    2.3 k 记录斐波那契数组的下标
    2.4 mid 记录中间下标
    2.5 f[] 斐波那契数组
  3. 判断 right > f[k] - 1 { k++; } 补长 arr 数组 —> temp
  4. 将数组后面补长的内容使用最后一个数填充.
  5. 当 left <= right 时,进入循环判断
  6. 计算出 mid 值: mid = left + f[k-1] -1
  7. 比较 midValue 与 findValue 的大小
    7.1 midValue > findValue
    7.1.1 将右边界更新: right = mid - 1;
    7.1.2 将斐波那契数组下标更新: k–;
    7.2 midValue < findValue
    7.2.1 将左边界更新 : left = mid + 1;
    7.2.2 将斐波那契数组下标更新: k -= 2;
    7.3 midValue == findValue
    7.3.1 mid、right 返回小的一个
1. 二分查找

    /**
     *  二分查找前提--有序数组
     */
    @Test
    public void testBinarySearch(){
        int [] arr = {1,5,8,10,45,96,96,96,100};
        System.out.println(BinarySearch(arr, 0, arr.length - 1, 96));
//        System.out.println(BinarySearch2(arr, 0, arr.length - 1, 101));

    }

    /**
     *  二分查找
     * @param arr   数组
     * @param left  左边界
     * @param right   右边界
     * @param findValue   需要查找的值
     * @return
     */
    public int BinarySearch(int [] arr, int left , int right, int findValue){
        // 判断结束条件
        if(left > right){
            return -1;
        }
        int mid = (left + right) / 2;
        int midValue = arr[mid];

        if(left <= right){
            if(midValue < findValue){
                return BinarySearch(arr, mid + 1, right, findValue);
            }else if(midValue > findValue){
                return BinarySearch(arr, left, mid - 1, findValue);
            }else {
                // 找到了
                return mid;
            }
        }
        return -1;
    }

如果需要返回找到的所有的下标。


    /**
     *  可以返回找到的所有下标
     * @param arr
     * @param left
     * @param right
     * @param findValue
     * @return
     */
    public List<Integer> BinarySearch2(int [] arr, int left , int right, int findValue){
        // 判断结束条件
        if(left > right){
            return Collections.singletonList(-1);
        }
        int mid = (left + right) / 2;
        int midValue = arr[mid];

        if(left <= right){
            if(midValue < findValue){
                return BinarySearch2(arr, mid + 1, right, findValue);
            }else if(midValue > findValue){
                return BinarySearch2(arr, left, mid - 1, findValue);
            }else {
                List<Integer> list = new ArrayList<>();
                // 找到了
                // 继续向前或者向后查找
                int temp = mid;
                while (temp > 0 && arr[temp] == findValue){
                    list.add(temp);
                    // 往前
                    temp--;
                }
                temp = mid+1;
                while(temp < arr.length && arr[temp] == findValue){
                    list.add(temp);
                    temp++;
                }
                return list;
            }
        }
        return Collections.singletonList(-1);
    }


2. 插值查找

    /**
     *  插入查找
     * @param arr    数组
     * @param left   左边界
     * @param right  右边界
     * @param findValue  需要查找的值
     * @return  数组下标
     */
    public int insertValueSearch(int [] arr, int left, int right, int findValue){
        // 结束判断条件 缺一不可
        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]);
        int midValue = arr[mid];

        if(left <= right){
            if(findValue < midValue){
                return insertValueSearch(arr, left, mid - 1, findValue);
            }else if(findValue > midValue){
                return insertValueSearch(arr, mid + 1, right, findValue);
            }else {
                // 找到了
                return mid;
            }
        }
        return  -1;
    }


    @Test
    public void testInsertValueSearch(){
        int [] arr = new int[100];
        for (int i = 1 ; i <= 100; i++){
            arr[i-1] = i;
        }

        System.out.println(insertValueSearch(arr, 0, arr.length - 1, 85));

    }


3. 斐波那契查找(黄金分割点法查找)
    // 定义斐波那契数列的数组大小
    static int maxSize = 20;
    /**
     *  获取斐波那契数列
     * @return
     */
    public int[] getFib(){
        int [] arr = new int[maxSize];
        arr[0] = 1;
        arr[1] = 1;
        for (int i = 2; i < maxSize ; i++){
            arr[i] = arr[i-1] + arr[i-2];
        }
//        System.out.println(Arrays.toString(arr));
        return arr;
    }

    /**
     *  斐波那契查找
     *  黄金分割点法查找
     * @param arr  数组
     * @param findValue   需要查找的值
     * @return
     */
    public int FibSearch(int[] arr,  int findValue){
        // 结束
        int left = 0;
        int right = arr.length - 1;
        int k = 0;   // 表示斐波那契数组的下标
        int mid = 0;  // 存放中间值
        int[] f = getFib();  // 获取斐波那契数列

        // 获取到斐波那契分割数值的下标
        while (right > f[k] - 1){
            k++;
        }
        // 不足的会自动用 0 补充的
        int[] temp = Arrays.copyOf(arr, f[k]);

        for (int i = arr.length ; i < f[k] ; i++){
            temp[i] = arr[arr.length - 1];
        }

        while(left <= right){
            mid  = left + f[k-1] - 1;
            if(temp[mid] < findValue){
                left = mid + 1;
                k -= 2;
            }else if(temp[mid] > findValue){
                right = mid - 1;
                k --;
            }else {
                // 找到了
                if(mid <= right){
                    return mid;
                }else {
                    return right;
                }
            }
        }
        return -1;
    }


    @Test
    public void testFibSearch(){
        int [] arr = {1,5,8,10,65,78,96,100};
        System.out.println(FibSearch(arr, 100));

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值