算法

2019-10-19  本文已影响0人  passiontim

二分查找的总结


普通的二分查找

最普通的写法:

image.png
    static int bs1(int[] arr,int key){
        int L = 0,R = arr.length - 1; //在[L,R]范围内寻找key
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] == key)
                return mid;
            if(arr[mid] > key)
                R = mid - 1;// key 在 [L,mid-1]内
            else
                L = mid + 1;
        }
        return -1;
    }

普通二分查找的另一种写法

首先说明,这个和上面的二分查找是完全一样的,只不过我们定义的区间不同而已:

    //和上面的完全一样,只是一开始R不是arr.length-1 而是arr.length
    static int bs2(int[] arr,int key){
        int L = 0, R = arr.length; //注意这里R = arr.length 所以在[L,R)开区间中找
        int mid;
        while( L < R){ //注意这里 不是 L <= R
            mid = L + (R - L)/2;
            if(arr[mid] == key)
                return mid;
            if(arr[mid] > key)
                R = mid; // 在[L,mid)中找
            else
                L = mid + 1;
        }
        return -1;
    }

上面的两种方式一般还是第一种方式用的多一点。


第一个=key的,不存在返回-1

这个和之前的不同是:

举个例子:

image.png
    /**查找第一个与key相等的元素的下标, 如果不存在返回-1 */
    static int firstEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1; //在[L,R]查找第一个>=key的
        int mid;
        while( L <= R){
            mid = L + (R - L)/2;
            if(arr[mid] >= key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        if(L < arr.length && arr[L] == key)
            return L;
        return -1;
    }


第一个>=key

这个和上面那个寻找第一个等于key的唯一的区别就是:

    /**查找第一个大于等于key的元素的下标*/
    static int firstLargeEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] >= key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        return L;
    }

第一个>key

这个和上两个的不同在于:

举个例子:

image.png
    /**查找第一个大于key的元素的下标 */
    static int firstLarge(int[] arr,int key){
        int L = 0,R = arr.length - 1;
        int mid;
        while(L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] > key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        return L;
    }


<font color =red>第一个...的总结

上面写了三个第一个.....的程序,可以发现一些共同点 ,也可以总结一下它们微妙的区别:


最后一个=key的,不存在返回-1

和寻找第一个 = key的很类似,不过是方向的不同而已:

举个例子:

image.png
    /**查找最后一个与key相等的元素的下标, 如果没有返回-1*/
    static int lastEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L)/2;
            if(arr[mid] <= key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        if(R >= 0 && arr[R] == key)
            return R;
        return -1;
    }

最后一个<=key

这个和上面那个寻找最后一个等于key的唯一的区别就是:

    /**查找最后一个小于等于key的元素的下标 */
    static int lastSmallEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] <= key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        return R;
    }

最后一个<key

这个和上面两个不同的是:

[图片上传失败...(image-c6ae4-1571461689829)]

    /**查找最后一个小于key的元素的下标*/
    static int lastSmall(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while(L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] < key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        return R;
    }


<font color =red>最后一个...的总结

上面三个都是求最后一个.....的,也进行一下总结:


完整测试代码

public class BinarySearch {

    //最普通的二分搜索法
     static int bs1(int[] arr,int key){
        int L = 0,R = arr.length - 1; //在[L,R]范围内寻找key
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] == key)
                return mid;
            if(arr[mid] > key)
                R = mid - 1;// key 在 [L,mid-1]内
            else
                L = mid + 1;
        }
        return -1;
    }

    //和上面的完全一样,只是一开始R不是arr.length-1 而是arr.length
     static int bs2(int[] arr,int key){
        int L = 0, R = arr.length; //注意这里R = arr.length 所以在[L,R)开区间中找
        int mid;
        while( L < R){ //注意这里 不是 L <= R
            mid = L + (R - L)/2;
            if(arr[mid] == key)
                return mid;
            if(arr[mid] > key)
                R = mid; // 在[L,mid)中找
            else
                L = mid + 1;
        }
        return -1;
    }


    /**查找第一个与key相等的元素的下标, 如果不存在返回-1 */
     static int firstEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1; //在[L,R]查找第一个>=key的
        int mid;
        while( L <= R){
            mid = L + (R - L)/2;
            if(arr[mid] >= key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        if(L < arr.length && arr[L] == key)
            return L;
        return -1;
    }

    /**查找第一个大于等于key的元素的下标*/
    static int firstLargeEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] >= key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        return L;
    }


    /**查找第一个大于key的元素的下标 */
    static int firstLarge(int[] arr,int key){
        int L = 0,R = arr.length - 1;
        int mid;
        while(L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] > key)
                R = mid - 1;
            else
                L = mid + 1;
        }
        return L;
    }


    /**查找最后一个与key相等的元素的下标, 如果没有返回-1*/
     static int lastEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L)/2;
            if(arr[mid] <= key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        if(R >= 0 && arr[R] == key)
            return R;
        return -1;
    }

    /**查找最后一个小于等于key的元素的下标 */
    static int lastSmallEqual(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while( L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] <= key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        return R;
    }


    /**查找最后一个小于key的元素的下标*/
    static int lastSmall(int[] arr,int key){
        int L = 0, R = arr.length - 1;
        int mid;
        while(L <= R){
            mid = L + (R - L) / 2;
            if(arr[mid] < key)
                L = mid + 1;
            else
                R = mid - 1;
        }
        return R;
    }


    public static void main(String[] args) {

        int[] arr = {1,3,4,6,6,6,6,6,6,8,9};

        System.out.println("----------general-----------");

        System.out.println(bs1(arr,3));//1
        System.out.println(bs2(arr,3));//1
        System.out.println(bs2(arr,6));//5


        System.out.println("-----------first------------");

        //第一个 =  的
        System.out.println(firstEqual(arr,6));//3

        //第一个 >= 的
        System.out.println(firstLargeEqual(arr,5));//3
        System.out.println(firstLargeEqual(arr,6));//3

        //第一个 > 的
        System.out.println(firstLarge(arr,6));//9

        System.out.println("------------last------------");

        //最后一个 =  的
        System.out.println(lastEqual(arr,6));//8

        // 最后一个 <= 的
        System.out.println(lastSmallEqual(arr,7));//8
        System.out.println(lastSmallEqual(arr,6));//8

        //最后一个 < 的
        System.out.println(lastSmall(arr,6));//2

    }
}

效果:
[图片上传失败...(image-3b5bd9-1571461689829)]

上一篇 下一篇

猜你喜欢

热点阅读