Java基础查找算法(2)——二分查找(折半查找)

Java基础查找算法(2)——二分查找(折半查找)

1.二分查找简述

二分查找,又称折半查找.这个查找有个前提条件:所查数组已经有序

假设:

  • 所查数组:arr

  • 查询目标值:target

  • 数组的最左下标 left

  • 数组的最右下标 right

    由上可取中间下标:mid=(left + right) / 2

    可以使用递归来实现二分查找:

    参数:所查数组:arr,查询目标值:target,数组的最左下标 left,数组的最右下标 right

    sort(int[] arr, int left, int right, int target)

排序思路:找到数组arr中间的数(arr[mid])与目标值比较:

  • 若中间值arr[mid]<目标值target,说明目标值只可能在数组右半边,递归右半边数组search(arr, mid + 1, right, target);
  • 若中间值arr[mid]>目标值target,说明目标值只可能在数组左半边,递归左半边数组search(arr, left, mid - 1, target)
  • 若中间值arr[mid]=目标值target,即可将下标添加到目标值下标集合中,扫描该坐标左右两边相邻数据,相等则添加到目标值下标集合中即可.

上面加粗只可能,是因为数组可能没有查询目标值.

2.二分查找代码实现

2.1简介代码(无注释)

private static List<Integer> result = new ArrayList<>();
public static List<Integer> search(int[] arr, int left, int right, int target) {
        if (left > right) return result;
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (target > midVal) return search(arr, mid + 1, right, target);
        else if (target < midVal) return search(arr, left, mid - 1, target);
        else {
            result.add(mid);
            int temp = mid - 1;
            while (true) {
                if (temp < 0 || arr[temp] != target) break;
                result.add(temp);
                temp -= 1;
            }
            temp = mid + 1;
            while (true) {
                if (temp > arr.length - 1 || arr[temp] != target) break;
                result.add(temp);
                temp += 1;
            }
            return result;
        }
    }

2.2 完整代码(含注释与运行实例)

由于使用二分查找需要先排序好数组,为了代码简洁,我直接调用了之前写过得基数排序

Java基础排序算法(8)——基数排序

package Algorithm.Search;

import Algorithm.Sort.RadixSort;
import Algorithm.Sort.Template;
import Utils.ArrUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 查找(2)
 * 二分查找(折半查找)
 * 前提是数组本身是有序的
 */
public class BinarySearch {
    private static List<Integer> result = new ArrayList<>();

    /**
     * 查找函数
     *
     * @param arr    需查找的数组
     * @param left   数组的最左下标
     * @param right  数组的最右下标
     * @param target 需要查找的元素
     * @return
     */
    public static List<Integer> search(int[] arr, int left, int right, int target) {

        //递归结束条件:left>right 但没有找到目标值
        if (left > right) return result;

        int mid = (left + right) / 2;
        int midVal = arr[mid];//数组arr的中间值

        if (target > midVal) return search(arr, mid + 1, right, target);//右侧递归
        else if (target < midVal) return search(arr, left, mid - 1, target);//左侧递归
        else {//return mid;//刚好是中间值
            //重复目标值
            result.add(mid);//添加中间值

            //左边扫描 添加左边与之相同的值
            int temp = mid - 1;
            while (true) {
                if (temp < 0 || arr[temp] != target) break;//下标越界或不为目标值
                result.add(temp);//添加下标
                temp -= 1;//左移
            }
            //右边扫描 添加右边与之相同的值
            temp = mid + 1;
            while (true) {
                if (temp > arr.length - 1 || arr[temp] != target) break;//下标越界或不为目标值
                result.add(temp);//添加下标
                temp += 1;//右移
            }

            return result;//返回下标集合
        } //else


    }

    public static void main(String[] args) {
        int testSize = 20;
        int[] arr = Template.getIntData(testSize);
        //输出原数组
        ArrUtil.show(arr);
        RadixSort.sort(arr);//需要目标数组有序 调用基数排序
        ArrUtil.show(arr);
        int a = (int) (Math.random() * testSize);

        System.out.println("二分查找" + a);

        List<Integer> index = search(arr, 0, arr.length - 1, a);

        System.out.println("下标" + index);

    }


}

3.运行实例

12 7 15 16 17 0 9 16 10 14 15 3 18 6 12 17 6 0 17 11 
0 0 3 6 6 7 9 10 11 12 12 14 15 15 16 16 17 17 17 18 
二分查找12
下标[9, 10]
发布了67 篇原创文章 · 获赞 32 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42391904/article/details/101316027