1. 简介
本篇文章主要讲稍微复杂一点的二分查找,这里的复杂是指在存在重复元素的有序数组中查找符合要求的值,主要探讨4种查找的情况。
- 二分查找,查找第一个等于给定值元素的索引
- 二分查找,查找最后一个等于给定值元素的索引
- 二分查找,查找第一个大于等于给定值元素的索引
- 二分查找,查找最后一个小于等于给定值元素的索引
2.内容
针对上面的四种情况,下面具体阐述一下个人的见解。个人认为这4种查找主要是对于分界点的处理,1.当中间指针指向数组的最小值,即 mid=0;2.当中间指针指向数组的最大值,即 mid=n;3. 当a[mid-1] 或a[mid+1]和a[mid]的值不相同时候的处理。
2.1 查找第一个等于给定值元素的索引
2.1.1 代码
// 二分查找,查找第一个等于给定值元素的索引
// 对于这种情况,a[mid] < value 和 a[mid] > value 这两种情况和简单的二分查找相同
// 主要就是 a[mid] == value 这种情况需要仔细处理一下
public int binarySearch(int[] a, int value) {
if(a == null){
return -1;
}
int low = 0, hi = a.length - 1;
while (low <= hi) {
int mid = low + ((hi - low) >> 1);
if (a[mid] < value) {
low = mid + 1;
} else if (a[mid] > value) {
hi = mid - 1;
} else {
// a[mid] == value 的情况
// 满足如下两种情况,则找到相应的值
// 1. mid == 0,说明已经到数组最小值的边界,a[0]==value,返回mid(0) 即可。
// 2. a[mid - 1] != value 而 a[mid] == value,说明 mid为分界点,返回mid即可。
if((mid == 0) || (a[mid - 1] != value)) return mid;
else hi = mid - 1;
}
}
return -1;
}
2.2 查找最后一个等于给定值元素的索引
2.2.1 代码
//二分查找,查找最后一个等于给定值元素的索引
// 对于这种情况,a[mid] < value 和 a[mid] > value 这两种情况和简单的二分查找相同
// 主要就是 a[mid] == value 这种情况需要仔细处理一下
public int binarySearch(int[] a, int value) {
if(a==null){
return -1;
}
int n = a.length - 1;
int low = 0, hi = n;
while(low <= hi){
int mid = low + ((hi - low) >> 1);
if(a[mid] < value){
low = mid + 1;
}else if(a[mid] > value){
hi = mid - 1;
}else{
// a[mid] == value 的情况
// 满足如下两种情况,则找到相应的值
// 1. mid == n,说明已经达到数组最大值的边界,a[n]==value,返回mid(n)即可。
// 2. a[mid + 1] != value,而a[mid] == value,说明mid为分界点,返回mid即可。
if((mid == n) || (a[mid + 1] != value)) return mid;
else low = mid + 1;
}
}
return -1;
}
2.3 查找第一个大于等于给定值元素的索引
2.3.1 代码
//二分查找,查找第一个大于等于给定值元素的索引
//只需要分两种情况
// 1. a[mid] >= value,说明数组中存在符合条件的值,需要找到分界点。
// 2. a[mid] < value,此时不能确定数组中有无符合条件的值,继续缩小范围low = mid + 1;
public int binarySearch(int[] a, int value) {
if(a==null){
return -1;
}
int n = a.length - 1;
int low = 0;
int high = n;
while (low <= high) {
int mid = low + ((high - low) >> 1);
//a[mid] >= value成立
if (a[mid] >= value) {
// 满足如下两种情况,则找到相应的值
// 1. mid == 0,说明已经到达到数组最小值的边界,a[0]>=value,返回mid(0)即可。
// 2. a[mid - 1] < value,而a[mid]>=value,说明当前mid为分界点,返回mid即可
if ((mid == 0) || (a[mid - 1] < value))return mid;
else
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
2.4 查找最后一个小于等于给定值元素的索引
2.4.1 代码
// 二分查找,查找最后一个小于等于给定值元素的索引
// 只需要分两种情况
// 1.a[mid] <= value,说明数组中存在符合条件的值,需要找到分界点。
// 2.a[mid] > value,此时不能确定数组中有无符合条件的值,继续缩小范围high = mid - 1;
public int binarySearch(int[] a, int value) {
if(a==null){
return -1;
}
int n = a.length - 1;
int low = 0;
int high = n;
while (low <= high) {
int mid = low + ((high - low) >> 1);
//a[mid] <= value成立。
if(a[mid] <= value){
//满足如下两种情况,则找到相应的值
//1. mid == n,说明已经达到数组最大值的边界,a[n]<=value,返回mid(n)即可
//2. a[mid + 1] > value,而a[mid] <= value,说明mid为分界点,返回mid即可
if((mid == n) || a[mid + 1] > value)return mid;
else low = mid + 1;
}else{
high = mid - 1;
}
}
return -1;
}
3.声明
这篇文章其实只能算半个原创,在极客时间王争讲解的《数据结构与算法之美》(付费文章无法给出链接)中他在讲解之前让我们试着自己实现一下,笔者也自己实现了相应的功能,但代码确实有些不够简洁,看了他的代码后确实简洁,于是写出了自己的一些见解。
4272

被折叠的 条评论
为什么被折叠?



