Java中的二分查找

在Java.util中有两个类,Arrays和Collectons,可以方便快捷的帮我们处理一些数组和集合的问题。

它们里边都一个一个二分法查找的方法:

Arrays.binarySearch

    public static int binarySearch(long[] a, long key) {
        return binarySearch0(a, 0, a.length, key);
    }
    private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                                     long key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            long 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.
    }

Collections.binarySearch:

    public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }
    private static <T>
    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        int low = 0;
        int high = list.size()-1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable<? super T> midVal = list.get(mid);
            int cmp = midVal.compareTo(key);

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

其核心算法是一致的,区别就在于Arrays支持数组,Collectons针对的是实现List接口的集合。

public class BinarySearch {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        int i = 1;
        while(i<10) {
            list.add(i);
            i++;
        }
        Integer key=11;

        Integer result = binarySearch(list, key);
        System.out.println(result);
        
        
        
    }

    private static Integer binarySearch(List<Integer> list, Integer key) {
        int min = 0;
        int max = list.size()-1;
        while(min<max) {
            int mid = (max+min)>>>1;
            Integer integer = list.get(mid);
            int compareTo = integer.compareTo(key);
            if(compareTo<0) {
                //代表我们查询的这一半中的最大值都小于我们要找的元素
                min=mid+1;
            }else if(compareTo>0) {
                //代表我们要查询的这一半中可能由我们要找的元素
                max=mid-1;
            }else {
                return mid;//直到找到中间的那一个
            }
        }
        return -(min+1);
    }
}

1.首先确定最大索引和最小索引

2.以min<max为条件做循环判断,每次都获取一个中间索引。然后获取这个索引所对应的元素和我们要查找的数值进行判断。

在判断时调用的时Integer这个类的compareTo方法进行比较。所有想要调用这个方法的类只需要实现Comparable这个接口

然后就可以自定义自己的compareTo方法。(这个接口是一个进行比较的规则,里边也就只有compareTo这一个方法)。

在Integer中这个方法是这样实现的:

public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

也就是使用三元运算法则对两个值进行比较,如果元素小于我们要找的值,返回-1,如果元素大于我们要找的值返回1,如果找到了,就返回0.

3.如果我们mid对应的元素小于我们要找的元素,那么就去另一半寻找,最小索引变为mid+1;

如果我们mid对用的元素大于我们要找到元素,那么说明元素可能在这半个区间中,缩小范围继续寻找,将max变为mid-1;

如果我们要找的值在集合和数组中不存在,就返回一个负值。值的大小为-(中间索引数+1);

 需要注意的是,因为二分法查找是元素大小进行判断的,所以要想是结果正确,首先要对集合进行一次排序。

posted @ 2018-02-28 20:47  一介書生  阅读(130)  评论(0)    收藏  举报