数据结构与算法(黑马)

二分查找

二分查找基础版

需求:在有序数组A内,查找值 $target$

  • 如果找到返回索引

  • 如果找不到返回 -1

数据结构与算法(黑马)_第1张图片

public static int binarySearchBasic(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length-1;//i~j范围内有东西
        while (i <= j) {
            int m = (i + j) >>> 1;//无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
            if(target < a[m]){//目标在左边
                j= m - 1;
            }else if(a[m] < target){//目标在右边
                i= m + 1;
            }else {
                return m;//找到了
            }
        }
        return -1;//没找到
    }
    /*
        问题1:为什么是i<=j意味着区间内有未比较的元素,而不是i>> 1,无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
        问题3:都写成小于号有啥好处?
        跟人类思维更一致
    */

问题1:为什么是i<=j意味着区间内有未比较的元素,而不是i

i,j它们指向的元素也会参与比较,因为i,j指向的也有可能是查找目标。

问题2:(i + j) / 2 有没有问题?

最大值相加超出范围会出现负数,同一个二进制数,不把最高位视为符号位,把最高位视为符号位,代表结果不同,java会将最高位视为符号位 (i + j) >>> 1,无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位。

问题3:都写成小于号有啥好处?

跟人类思维更一致。

二分查找改动版

public static int binarySearchBasic2(int [] a,int target){
        int i = 0;
        int j = a.length;       //第一处 j只是一个边界,它指向的一定不是查找目标,i指向的可能是查找目标
        while (i < j) {         //第二处 如果查找数组内没有的元素i<=j会陷入死循环,因为j指向的一定不是查找目标,所以不用参与比较
            int m = (i + j) >>> 1;
            if(target < a[m]){
                j = m ;          //第三处
            }else if(a[m] < target){
                i= m + 1;
            }else {
                return m;
            }
        }
        return -1;//没找到
    }

二分查找法算法运行语句总次数( floor( log_2(n) )+1)* 5+ 4

线性查找法

public static int linearSearch(int[] a,int target){
        for (int i = 0; i < a.length; i++) {
            if(a[i] == target){
                return i;
            }
        }
        return -1;
    }
    //1.最差的执行情况
    //2.假设每行执行时间一样
    //算法运行语句总次数:3*n + 3

线性查找法算法运行语句总次数 3*n + 3

在数据量比较大的情况下二分查找法运行次数比线性查找发低得多


时间复杂度

数据结构与算法(黑马)_第2张图片

 大O表示数据结构与算法(黑马)_第3张图片

数据结构与算法(黑马)_第4张图片

 常见大O表示法数据结构与算法(黑马)_第5张图片

 数据结构与算法(黑马)_第6张图片

数据结构与算法(黑马)_第7张图片 数据结构与算法(黑马)_第8张图片


 二分查找平衡版

假设已知循环了L次,目标在最左边就会比较L次,目标在最右边就会比较2L次,所以二分查找现在有一个问题就是左边查找元素,右边查找元素并不是平衡的 

/**
     * 二分查找平衡版
     * @param a
     * @param target
     * @return
     */
    public static int binarySearchBasic3(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length;//i~j范围内有东西
        //假设循环了L次 元素在最左边 比较L次  元素在最右边 比较2L次
        //二分查找现在一个问题就是左边找元素,右边找元素并不是平衡的
        while(1 < j - i){
            int m = (i + j) >>> 1;
            if(target < a[m]){
                j = m;
            }else{
                i = m;
            }
        }
        if(target == a[i]){
            return i;
        }else{
            return -1;
        }
    }

数据结构与算法(黑马)_第9张图片


二分查找java版

private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

返回的是-插入点-1

如果要插入

public static void main(String[] args) {
        int[] a = {2,4,6,8,9};
        int key = 3;
        //{0,0,0,0,0,0}
        int i = Arrays.binarySearch(a,key);

        if(i < 0){
            int insertIndex = Math.abs(i + 1);
            int[] b = new int[a.length+1];
            System.arraycopy(a,0,b,0,insertIndex);
            b[insertIndex] = key;
            System.arraycopy(a,insertIndex,b,insertIndex+1,a.length-insertIndex);
            System.out.println(Arrays.toString(b));
        }
    }

二分查找Leftmost 

/**
     * 二分查找Leftmost
     * @param a
     * @param target
     * @return
     */
    public static int binarySearchBasic4(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length-1;//i~j范围内有东西
        int candidate = -1;//候选者
        while (i <= j) {
            int m = (i + j) >>> 1;//无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
            if(target < a[m]){//目标在左边
                j= m - 1;
            }else if(a[m] < target){//目标在右边
                i= m + 1;
            }else {
                //记录候选位置
                candidate = m;
                j = m - 1;
            }
        }
        return candidate;//没找到
    }

/**
     * 二分查找Leftmost改动
     * @param a
     * @param target
     * @return
     */
    public static int binarySearchBasic6(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length-1;//i~j范围内有东西
        int candidate = -1;//候选者
        while (i <= j) {
            int m = (i + j) >>> 1;//无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
            if(target <= a[m]){//目标在左边
                j= m - 1;
            }else{//目标在右边
                i= m + 1;
            }
        }
        return i;//返回≥target最靠左索引
    }

二分查找Rightmost 

/**
     * 二分查找Rightmost
     * @param a
     * @param target
     * @return
     */
    public static int binarySearchBasic5(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length-1;//i~j范围内有东西
        int candidate = -1;//候选者
        while (i <= j) {
            int m = (i + j) >>> 1;//无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
            if(target < a[m]){//目标在左边
                j= m - 1;
            }else if(a[m] < target){//目标在右边
                i= m + 1;
            }else {
                //记录候选位置
                candidate = m;
                i = m + 1;
            }
        }
        return candidate;//没找到
    }

/**
     * 二分查找Rightmost改动版
     * @param a
     * @param target
     * @return
     */
    public static int binarySearchBasic7(int [] a,int target){
        int i = 0;//设置指针和初值
        int j = a.length-1;//i~j范围内有东西
        int candidate = -1;//候选者
        while (i <= j) {
            int m = (i + j) >>> 1;//无符号右移1位都可以看作除2向下取整,java中除法会自动取整 m = (i+j)/2 有问题不会动符号位
            if(target < a[m]){//目标在左边
                j= m - 1;
            }else {
                i = m + 1;
            }
        }
        return i - 1;//返回≤target最靠右索引
    }

你可能感兴趣的:(数据结构,算法,java)