一:问题描述
当我们在用二分法查找元素的时候,我们往往特希望遇到是奇数个元素个数的数组,因为划分完左右两边的个数相等,所以在以前刚学二分法的时候就有这个疑问,当时就是模模糊糊过去了,再遇到其实还是会有疑问。现在实例验证遇见偶数个数数组元素个数时的二分法
二:思路+示例
目标:查询数组当中是否存在某个数,存在返回其下标,不存在返回-1;
思路:1.这是一个很典型的二分查找的例子,但关键的是我们要考虑其中的符号问题
2.也就是左闭右闭,左闭右开,左开右闭,这是二分法的重点,
3.我们一般使用的是左闭右闭,即[left,right],
举例如:
输入偶数个的数组array[7]: 我们想要查询29是否存在
1 5 9 11 23 29 31 50
1>:我们在选取middle时 middle = 7/2 = 3 取下标为3的元素也就是11,
2>:这时划分的数组左右长度不一样,跟我们常规的奇数个的时候不一样,这时我们对左右两边
个数的考虑是多余的,因为我们每次都是将middle左边(右边)的所有元素均排除,跟个数
完全没有关系,
3>:回到上方的例子当中,我们比较29和11的时候直接将左边的所有元素pass掉
下一次比较[middle+1,right]当中的元素,这里左右两边均取闭区间即左闭右闭
三:上码
/**
目标:查询数组当中是否存在某个数,存在返回其下标,不存在返回-1;
思路:1.这是一个很典型的二分查找的例子,但关键的是我们要考虑其中的符号问题
2.也就是左闭右闭,左闭右开,左开右闭,这是二分法的重点,
3.我们一般使用的是左闭右闭,即[left,right],
举例如:
输入偶数个的数组array[7]: 我们想要查询29是否存在
1 5 9 11 23 29 31 50
1>:我们在选取middle时 middle = 7/2 = 3 取下标为3的元素也就是11,
2>:这时划分的数组左右长度不一样,跟我们常规的奇数个的时候不一样,这时我们对左右两边
个数的考虑是多余的,因为我们每次都是将middle左边(右边)的所有元素均排除,跟个数
完全没有关系,
3>:回到上方的例子当中,我们比较29和11的时候直接将左边的所有元素pass掉
下一次比较[middle+1,right]当中的元素,这里左右两边均取闭区间即左闭右闭
**/
#include<bits/stdc++.h>
using namespace std;
int find(int a[],int size,int target){
int left = 0;
int right = size - 1;//因为采用的左闭右闭,比如a[5],那么左右边界就是[0,4]
int mid;
while(left <= right){ //当left == right时候 左闭右闭依然有效
mid = left + (right - left)/2;//这里等价于 (right + left)/2
if(a[mid] > target){
right = mid - 1;
}else if (a[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;//没找到
}
int main(){
int a[10];
int N,target;//N个数和要查询的数
cin >> N >> target;
for(int i = 0; i < N; i++){
cin >> a[i];
}
int res = find(a,N,target);
cout << res;
}
四:补充左闭右开
1:左闭右开[left,right)
即相应的while条件中(left < right) 而当a[mid] > target;时候,对应的 right = mid;
上码:
int search(int nums[], int size, int target)
{
int left = 0;
int right = size; //定义target在左闭右开的区间里,即[left, right)
while (left < right) { //因为left = right的时候,在[left, right)区间上无意义
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle; //target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
// 没找到就返回-1
return -1;
}