常规二分法
public int bSearch(int[] a, int n, int value){
int low = 0;
int high = n-1;
while (low <= high) {
int mid = (low + high)/2;
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
注意循环条件
注意是 low <= high,而不是 low < high。
当low = high的时候,查找区间内还有一个数字需要判断,如果循环条件是<的话,那么这种情况会退出循环返回-1。
例如[1,2,3]查2的情况
mid取值
mid=(low+high)/2的情况,当数字足够大时,有可能产生溢出的情况。应写成mid = low + (high - low)/2。
为了进一步优化性能,可采用位运算,改为mid = low + ((high - low)/2>>1)
low和high的更新
low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。
例如[1,5,7]查4的情况。
查找第一个值等于给定值的元素
public int bSearch(int[] a, int value) {
int left = 0;
int right = a.length - 1;
// 挤压右边界,返回左边界
while (left <= right) {
int mid = left + ((high - low) >> 1);
if (a[mid] >= value) {
high = mid -1;
} else {
low = mid + 1;
}
}
// 可能会右边越界,也可能数组中无目标数,需要做判断
if (low < n && a[low] == value) {
return low;
}
return -1;
}
查找最后一个值等于给定值的元素
public static int bSearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
// 挤压左边界,返回右边界
while (low <= high) {
int mid = high - ((high - low) >> 1);
if (a[mid] <= value) {
low = mid + 1;
} else {
high = mid - 1;
}
}
// 可能会在数组左边越界, 可能数组中无指定查找元素,需要做判断
if (high > 0 && a[high] == value) {
return high;
}
return -1;
}
public static int bSearch2(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = high - ((high - low) >> 1);
if (a[mid] < value) {
high = mid - 1;
} else if (a[mid] > value){
low = mid + 1;
} else {
if (mid == n - 1 || a[mid + 1] != value) {
return mid;
}else {
low = mid + 1;
}
}
}
return -1;
}
查找第一个大于等于给定值的元素
int erfenfirstlargeEqual(int arr,int key){
int L = 0, R = arr.size() - 1;
int mid;
// 与查找第一个等于的情况相似,挤压右边界,当右边界不满足时,返回左边界
while( L <= R){
mid = L + ((R - L) >> 1);
if(arr[mid] >= key)
R = mid - 1;
else
L = mid + 1;
}
// 判断是否越界
if(L < arr.length)
return L;
return -1;
}
查找最后一个小于等于给定值的元素
int erfenfirstlargeEqual(int arr,int key){
int L = 0, R = arr.size() - 1;
int mid;
// 与查找最后一个情况相似,挤压左边界,当左边界不满足时,返回右边界
while( L <= R){
mid = L + ((R - L) >> 1);
if(arr[mid] <= key)
L = mid + 1;
else
R = mid - 1;
}
// 判断是否越界
if(L < arr.length)
return L;
return -1;
}
查找数组中第一个大于key的数字
int erfenfirstLarge(vector<int> arr,int key){
int L = 0,R = arr.size() - 1;
int mid;
// 挤压右边界, 返回左边界
while(L <= R){
mid = L + ((R - L) >> 1);
if(arr[mid] > key)
R = mid - 1;
else
L = mid + 1;
}
return L;
}
查找数组中最后一个小于key的数字
int erfenlastSmall(vector<int> arr,int key){
int L = 0, R = arr.size() - 1;
int mid;
while(L <= R){
mid = L + ((R - L) >> 1);
if(arr[mid] < key)
L = mid + 1;
else
R = mid - 1;
}
return R;
}