1.通常情况下二分用于在一个有序的数组中寻找一个目标元素,这样的需求很明确,实现起来也比较简单:能找到目标元素则返回对应元素在数组中的下标,否则返回一个不存在的索引值。
代码如下:
static int binarySearch(int[] array, int target) { int left = 0; int right = array.length - 1; int mid; while (left <= right) { mid = (left + right) >> 1; if (array[mid] == target) { return mid; } else if (array[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return -1; }
(这里给出Arrays.java中的源码):
private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1; int 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. }
2.因为有序的集合里可能会存在多个元素相同的情况,所以可能会有以下两种需求:
求小于某个值的最大索引、求大于某个值的最小索引。比如:
给出一个有序的数组:[2,3,3,3,4,5]
小于4的最大索引是3,大于2的最小索引是1。
求小于某个值的最大索引代码如下:
static int binarySearch(int[] array, int target) { int left = 0; int right = array.length; int mid; while (left + 1 < right) { mid = (left + right) >> 1; if (array[mid] >= target) { right = mid - 1; } else { left = mid; } } return left; }
求大于某个值的最小索引代码如下:
static int binarySearch(int[] array, int target) { int left = 0; int right = array.length - 1; int mid; while (left < right) { mid = (left + right) >> 1; if (array[mid] <= target) { left = mid + 1; } else { right = mid; } } return left; }
这里给出说明,由于返回的索引值范围在0~array.length-1,因此可能会出现返回值是一个不符合要求的答案,需要自己判断。比如:
在求小于某个值的最大索引时:
对于数组[2,3,3,3,4,5],target=1时,返回值为0,很明显array[0]>1。
在求大于某个值的最小索引
对于数组[2,3,3,3,4,5],target=6时,返回值为5,很明显array[5]<6。
再有,如果条件变为小于等于某个值的最大索引或者大于等于某个值的最小索引时,只需要将判断条件中的>=变为>,<=变为<即可。