思路
二分查找也是前人研究很久后总结出来的,不必因为自己想不到而感到难过。
二分查找有个大前提:待查询的数组必须是有序的,这里以升序为例。
其思路很好理解,获取位于数组中间的值,与被查找值比较,因为数组的有序性,可以缩小查找的范围。这样一直这么查找,直到找到该值,或找不到。
类似小时候玩儿的一个猜数字游戏。卡片里写了一个从0~100
的数字,开始猜它是多少。
先猜是50
,被告知,比这个大。于是范围缩小为51~100
再猜是75
,被告知,比这个小。于是范围缩小为51~76
再猜是63
,被告知,比这个小。于是范围缩小为51~62
再猜是56
,被告知,回答正确。
可以用递归实现
递归实现
定义一个方法
public int binarySearch(int[] array, int left, int right, int value) {
if(left > right) {
return -1;
}
int mid = left + ((right-left)>>1);
if (array[mid] == value) {
return mid;
} else if (array[mid] > value) {
return binarySearch(array, left, mid - 1, value);
} else {
return binarySearch(array, mid + 1, right, value);
}
}
对外的方法
public int binarySearch(int[] array, int value) {
return binarySearch(array, 0, array.length, value);
}
循环实现
public int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] == value) {
return mid;
} else if (array[mid] > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
比较有趣的是下边这些实现
有序的数组中很有可能会有重复的元素,于是有了如下的问题
- 查找第一个等于指定值的元素索引
- 查找最后一个等于指定值的元素索引
- 查找第一个大于等于指定值的元素索引
- 查找最后一个小于等于给定值的元素索引
查找第一个等于指定值的元素索引
思路
原二分查找在找到一个元素后,检查与上一个元素是否相等
如果不相等,当前元素就是第一个
如果相等,相当于没找到目标元素,继续往前找,high = mid - 1
代码实现
public int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] == value) {
if(mid == 0 || array[mid-1] != value) {
return mid;
} else {
high = mid - 1;
}
} else if (array[mid] > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
查找最后一个等于指定值的元素索引
思路
原二分查找在找到一个元素后,检查与下一个元素是否相等
如果不相等,当前元素就是最后一个
如果相等,相当于没找到目标元素,继续往后找,low= mid + 1
代码实现
public int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] == value) {
if(mid == array - 1 || array[mid+1] != value) {
return mid;
} else {
low = mid + 1;
}
} else if (array[mid] > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
查找第一个大于等于指定值的元素索引
思路
原二分查找要变一下,因为这时可以合并大于和等于的情形了。相当于找一个大于等于指定值的元素索引(当然,判定下length-1
位置的元素是否比要查找的元素大,有了就返回,没有就返回-1
,不过别闹)
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] >= value) {
return mid;
} else {
low = mid + 1;
}
}
接着就和查找第一个等于指定值的元素索引类似了
检查上一个元素是否也大于等于指定值
如果不大于等于,当前元素就是第一个满足要求的元素
如果大于等于,相当于没找到目标元素,继续往前找,high = mid - 1
代码实现
public int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] >= value) {
if(mid == 0 || array[mid-1] < value) {
return mid;
} else {
high = mid - 1;
}
} else {
low = mid + 1;
}
}
return -1;
}
查找最后一个小于等于给定值的元素索引
思路
原二分查找要变一下,因为这时可以合并小于和等于的情形了。相当于找一个小于等于指定值的元素索引(也别闹)
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] <= value) {
return mid;
} else {
high = mid - 1;
}
}
接着就和查找最后一个等于指定值的元素索引类似了
检查下一个元素是否也小于等于指定值
如果不小于等于,当前元素就是最后一个满足要求的元素
如果小于等于,相当于没找到目标元素,继续往后找,low = mid + 1
代码实现
public int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (array[mid] <= value) {
if(mid == array.length - 1 || array[mid+1] > value) {
return mid;
} else {
low = mid + 1;
}
} else {
high = mid - 1;
}
}
return -1;
}