一:问题描述
当我们在用二分法查找元素的时候,我们往往特希望遇到是奇数个元素个数的数组,因为划分完左右两边的个数相等,所以在以前刚学二分法的时候就有这个疑问,当时就是模模糊糊过去了,再遇到其实还是会有疑问。现在实例验证遇见偶数个数数组元素个数时的二分法
二:思路+示例
目标:查询数组当中是否存在某个数,存在返回其下标,不存在返回-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)/2if(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;}} // 没找到就返回-1return -1;
}
参考自