【数据结构与算法(Java)】查找-二分查找(折半查找)

1. 查找思路

1.1 二分查找(递归实现,只返回第一个找到位置的下标)

  1. 基本条件:left > right,说明没找到,返回-1
  2. 得到中间点下标 mid
  3. 比较,分割,查找
    3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
    3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
    3.3 若 待寻找的数 = 中间点数值:找到,返回当前中间点下标

1.2 二分查找(递归实现,返回全部找到位置的下标)

  1. 新建list,存放要返回的全部下标值
  2. 基本条件:left > right,说明没找到,返回-1
  3. 得到中间点下标 mid
  4. 比较,分割,查找
    3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
    3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
    3.3 若 待寻找的数 = 中间点数值:找到,分别逐个查看找到位置左边和右边是否有相同值,将所有临近相同值的下标按顺序放入list:
    • 向左遍历,寻找相同值并按从小到大顺序加入list
    • 添加mid到list
    • 向右遍历,寻找相同值并按从小到大顺序加入list
    • 返回找到位置的全部下标list

2. 代码实现

2.1 递归实现

    /**
     * 二分查找(递归实现,只返回第一个找到位置的下标)
     * 二分法递归查找array里是否有searchValue,有则返回第一个发现点的下标,没有则返回-1
     *      思路:
     *          1. 基本条件:left > right,说明没找到,返回-1
     *          2. 得到中间点下标 mid
     *          3. 比较,分割,查找
     *              3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
     *              3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
     *              3.3 若 待寻找的数 = 中间点数值:找到,返回当前中间点下标
     * @param array - 要查找的数组
     * @param searchValue - 要查找的数值
     * @param left - 二分时左指针
     * @param right - 二分时右指针
     * @return - 找到返回第一个数值所在下标,没找到返回-1
     */
    public static int binarySearchByRecursion(int[] array, int searchValue, int left, int right) {
        // 1. 基本条件:left > right,说明没找到,返回-1
        if (left > right) {
            return -1;
        }

        // 2. 得到中间点下标 mid
        int mid = (left + right) / 2;

        // 3. 比较,分割,查找
        // 3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
        if (searchValue < array[mid]) {
            return binarySearchByRecursion(array, searchValue, left, mid - 1);
        }
        // 3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
        else if (searchValue > array[mid]) {
            return binarySearchByRecursion(array, searchValue, mid + 1, right);
        }
        // 3.3 若 待寻找的数 = 中间点数值:找到,返回当前中间点下标
        else {
            return mid;
        }
    }

    /**
     * 二分查找(递归实现,返回全部找到位置的下标)
     * 二分法递归查找array里是否有searchValue,有则返回所有满足的点的下标,没有则返回空list
     *      思路:
     *          0. 新建list,存放要返回的全部下标值
     *          1. 基本条件:left > right,说明没找到,返回-1
     *          2. 得到中间点下标 mid
     *          3. 比较,分割,查找
     *              3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
     *              3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
     *              3.3 若 待寻找的数 = 中间点数值:找到,分别逐个查看找到位置左边和右边是否有相同值,将所有临近相同值的下标按顺序放入list
     *                  (1) 向左遍历,寻找相同值并按从小到大顺序加入list
     *                  (2) 添加mid到list
     *                  (3) 向右遍历,寻找相同值并按从小到大顺序加入list
     *                  (4) 返回找到位置的全部下标list
     * @param array - 要查找的数组
     * @param searchValue - 要查找的数值
     * @param left - 二分时左指针
     * @param right - 二分时右指针
     * @return - 返回所有满足的点的下标,没有则返回空list
     */
    public static ArrayList<Integer> binarySearchForAllByRecursion(int[] array, int searchValue, int left, int right) {
        // 0. 新建list,存放要返回的全部下标值
        ArrayList<Integer> searchValueIndexList = new ArrayList<>();

        // 1. 基本条件:left > right,说明没找到,返回-1
        if (left > right) {
            return searchValueIndexList;
        }

        // 2. 得到中间点下标 mid
        int mid = (left + right) / 2;

        // 3. 比较,分割,查找
        // 3.1 若 待寻找的数 < 中间点数值:继续在中间点左边数组中查找
        if (searchValue < array[mid]) {
            return binarySearchForAllByRecursion(array, searchValue, left, mid - 1);
        }
        // 3.2 若 待寻找的数 > 中间点数值:继续在中间点右边数组中查找
        else if (searchValue > array[mid]) {
            return binarySearchForAllByRecursion(array, searchValue, mid + 1, right);
        }
        // 3.3 若 待寻找的数 = 中间点数值:找到,分别逐个查看找到位置左边和右边是否有相同值,将所有临近相同值的下标按顺序放入list
        else {
            // (1) 向左遍历,寻找相同值并按从小到大顺序加入list
            int index = mid - 1;
            Stack<Integer> leftIndexStack = new Stack<>();
            while (index >= 0 && searchValue == array[index]) {
                leftIndexStack.push(index);
                index--;
            }
            while (!leftIndexStack.isEmpty()){
                searchValueIndexList.add(leftIndexStack.pop());
            }
            // (2) 添加mid到list
            searchValueIndexList.add(mid);
            // (3) 向右遍历,寻找相同值并按从小到大顺序加入list
            index = mid + 1;
            while (index <= array.length - 1 && searchValue == array[index]) {
                searchValueIndexList.add(index);
                index++;
            }
            // (4) 返回找到位置的全部下标list
            return searchValueIndexList;
        }
    }

2.2 循环实现

    /**
     * 二分查找(loop实现,只返回第一个找到位置的下标)
     * 二分法循环查找array里是否有searchValue,有则返回第一个发现点的下标,没有则返回-1
     * @param array - 要查找的数组
     * @param searchValue - 要查找的数值
     * @return - 找到返回第一个数值所在下标,没找到返回-1
     */
    public static int binarySearchByLoop(int[] array, int searchValue) {
        int left = 0;
        int right = array.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (searchValue < array[mid]) {
                right = mid - 1;
            } else if (searchValue > array[mid]) {
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
    /**
     * 二分查找(递归实现,返回全部找到位置的下标)
     * 二分法循环查找array里是否有searchValue,有则返回所有满足的点的下标,没有则返回空list
     * @param array - 要查找的数组
     * @param searchValue - 要查找的数值
     * @return - 返回所有满足的点的下标,没有则返回空list
     */
    public static ArrayList<Integer> binarySearchForAllByLoop(int[] array, int searchValue) {
        ArrayList<Integer> searchValueIndexList = new ArrayList<>();
        int left = 0;
        int right = array.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (searchValue < array[mid]) {
                right = mid - 1;
            } else if (searchValue > array[mid]) {
                left = mid + 1;
            } else {
                // 向左遍历
                int index = mid - 1;
                Stack<Integer> leftIndexStack = new Stack<>();
                while (index >= 0 && searchValue == array[index]) {
                    leftIndexStack.push(index);
                    index--;
                }
                while (!leftIndexStack.isEmpty()) {
                    searchValueIndexList.add(leftIndexStack.pop());
                }
                // 添加mid
                searchValueIndexList.add(mid);
                // 向右遍历
                index = mid + 1;
                while (index <= array.length - 1 && searchValue == array[index]) {
                    searchValueIndexList.add(index);
                    index++;
                }
                return searchValueIndexList;
            }
        }
        return searchValueIndexList;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值