适用场景
适用于有序数组中查找某一个值.
每查找一次,就将搜寻范围缩小一半,
平均时间复杂度是O(logN), 简记作:O(lgN).
主要难点
主要难点在于边界条件的判断;
大致思路:
1.当供查找的数组不合法时,直接返回结果,查询无果;
2.当数组长度等于1时,直接判断是否相等即可;
3.当数组仅有两个元素时,直接分别判断;
4.当数组元素多于2个时, 采用如下策略:
1) 有限比较数组头尾两个元素与查询目标元素的值比较, 因为是有序数组,如果在界外,则直接判断给出查询结果;
2)如果和边界元素比较后,范围在界内,则开始真正的二分查找法,分别采用low, high, mid三个游标来界定查询范围.
实现方式
1.迭代法
2.递归法
3.Arrays.binarySearch(int[] arr, int target) API
实践代码如下:
import java.util.Arrays;/*** 默认有序数组arr[]是从小到大的顺序排列的,如果不是则需要先结合排序算法使用.*/
public class BinarySearch {// 迭代法public int binarySearch1(int[] arr, int target) {// 先判断数据的有效性if (arr == null || arr.length < 1) {return -1;}int low = 0;final int length = arr.length;int high = length - 1;int mid;// System.out.println("length:" + length + ",low:" + low + ",high:" + high// + ",mid:" + (low + high) / 2);// 先判断头尾游标的值if (length == 1) {if (arr[0] == target) {return 0;} else {return -1;// not found}} else { // length >= 2if (arr[low] == target) {return low;} else if (arr[high] == target) {return high;} else if (arr[low] > target || arr[high] < target) {//如果待查找的数值在有序数组最大或者最小值之外,直接判查询未果,无须再二分查找了.return -1;}}while (low < high) {mid = (low + high) / 2;// System.out.println("low:" + low// + ",value[low]:" + arr[low]// + ",high:" + high + ",value[high]:" + arr[high]// + ",mid:" + mid + ",value[mid]:" + arr[mid]);//这段非常重要,否则将可能出现死循环,//当头游标和尾游标的中间值已经是起始或者末尾两个游标位之一时,代表查找结束,且无果.if (high == mid || low == mid) {return -1;}if (arr[mid] < target) {low = mid;} else if (arr[mid] > target) {high = mid;} else if (arr[mid] == target) {return mid;}}return -1;}// 递归法public int binarySearch2(int[] arr, int target) {// System.out.println("enter binarySearch2");if (null == arr || arr.length < 1) {return -1;}final int length = arr.length;if (length == 1) {if (arr[0] == target) {return 0;} else {return -1;// not found}} else { // length >= 2if (arr[0] == target) {return 0;} else if (arr[arr.length - 1] == target) {return arr.length - 1;} else if (arr[0] > target || arr[length - 1] < target) {return -1;// not found}}return binarySearchRecursion(arr, 0, arr.length - 1, target);}private int binarySearchRecursion(int arr[], int low, int high, int target) {// System.out.println("length:" + arr.length + ",low:" + low + ",high:" + high// + ",mid:" + (low + high) / 2);int mid;while (low < high) {mid = (low + high) / 2;//这段非常重要,否则将可能出现死循环,//当头游标和尾游标的中间值已经是起始或者末尾两个游标位之一时,代表查找结束,且无果.if (mid == low || mid == high) {return -1;}if (arr[mid] == target) {return mid;} else if (arr[mid] < target) {return binarySearchRecursion(arr, mid, high, target);} else if (arr[mid] > target) {return binarySearchRecursion(arr, low, mid, target);}}return -1;}// Arrays.binarySearch API法public int binarySearchArrays(int[] arr, int target) {if (arr == null || arr.length <= 0) {return -1;}//Arrays.sort(arr);return Arrays.binarySearch(arr, target);}public static void main(String[] args) {// 多个测试用例数组int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,};int[] arr2 = {1, 2, 4,};int[] arr3 = {1, 2, 4, 6};int[] arr4 = {1, 2, 4, 6, 8};int[] bigArr = new int[10000];for (int i = 0; i < 10000; i++) {bigArr[i] = i * 2;}System.out.println("init arr done!");int wanted = 6;int[] toBeSearchArr = bigArr;BinarySearch bs = new BinarySearch();System.out.println("binearySearch1 :" + bs.binarySearch1(toBeSearchArr, wanted));System.out.println("binearySearch2 recursion :" + bs.binarySearch2(toBeSearchArr, wanted));System.out.println("Arrays.binarySearch():" + bs.binarySearchArrays(toBeSearchArr, wanted));}
}
测试结果如下:
init arr done!
binearySearch1 :3
binearySearch2 recursion :3
Arrays.binarySearch():3[Done] exited with code=0 in 1.508 seconds