比如现在有个记录名单的字典,里面的名字是按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); } }