比如现在有个记录名单的字典,里面的名字是按A-Z的顺序排好的,现在我想找Lily这个人。我可以从第一页开始一页一页的翻,但显然这样效率太低了。我可以怎么做呢?首先我直接翻到字典的中间位置,假如发现这里是字母H开头的,那么由于字典顺序是排好的,我就可以断定Lily肯定在后半本书里,前半本我就可以不看了。接着我翻到后半本书的中间,发现是字母N开头,那么我就可以断定,Lily是在这后半本书的前1/2里。依次类推,用不了几次,我就能找到Lily了。

以上所用的就是今天要说的二分查找法,可以看出,效率比一页一页的翻提高了太多。但这里我们也需要注意一点就是,我们之所以可以用这个方法查找Lily,是因为字典中的名字是排好序的,如果是乱序,用这种方法肯定就不行了。

这里我们以一个有序的数列来介绍这个查找法:比如要查找62这个数。

[3 17 21 37 45 52 62 78 83 95]

我们记录一个最高位95下标为9,最低位3下标为0,中间位下标=(最低位+最高位)/2取整,即为4.然后我们去中间位的数,也即下标为4对应的数45,由于45小于62,我们让最低位=中间位+1,也就是5,这样能重写中间位为(5+9)/2=7,也就取得了7对应的数78,78大于62,我们让最高位=中间位-1,也就是6,这样重写取中间位(5+6)/2=5,这样又取到了52,小于62,重写计算最低位为6,此时最高位等于最低位了,就得到了我们要的最终的值。当然如果在上一步计算的中间值正好是我们要的62,就讲这个数拿出就可了。

语言显得啰嗦且不一定能看懂,还是看代码吧:

package com.cloud.algorithm;
public class TestBinarySearch {
    public static int binarySearch(int[] arr,int dest){
        int lower = 0;
        int upper = arr.length;
        while (lower <= upper) {
            int mid = (lower + upper) / 2;
            if (arr[mid] < dest) {
                lower = mid + 1;
            } else if (arr[mid] > dest) {
                upper = mid - 1;
            }else {
                return mid;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] niArr = { 3, 17, 21, 37, 45, 52, 62, 78, 83, 95 };
        int niDestIndex = binarySearch(niArr, 62);
        if(niDestIndex==-1){
            System.out.println("没找到");
        }else{
            System.out.println("下标为:"+niDestIndex);
        }
    }
}

其实对于java而已,已经为我们封装太多的功能,提供了大量的算法:

package com.cloud.algorithm;
import java.util.Arrays;
public class TestArrays {
    public static void main(String[] args) {
        int[] niArr = { 78, 83, 17, 45, 52, 21, 3, 37, 62, 95 };
        // 将乱序的数组升序排列
        Arrays.sort(niArr);
        // 格式化输出排好序的数组
        System.out.println(Arrays.toString(niArr));
        // 在指定排好序数组中按照二分查找法查找某元素的下标
        int niIndex = Arrays.binarySearch(niArr, 62);
        System.out.println("所查元素下标为:"+niIndex);
    }
}