以下内容纯粹个人理解,如有误导你,怪我喽。。。
传统意义上老师讲授的二分就是一个思路,通过中间值mid来判断,
int search(int len,int val)
{
int l = 0,r = len-1,mid=0;
while(l<=r) //这里为什么是 <= 呢?而不是 < 呢?
{
mid = (l+r)/2;
if(arr[mid]==val)
return mid;
else if(arr[mid]<val)
l = mid + 1;
else
r = mid - 1;
}
return -1;
}
但是
你有没有考虑过结束的时候 l 和 r 的值呢?他们有什么用呢?
还有那个<=的判断条件,举个反例:当数组只有一个元素时,l = r,mid = (l + r)/2 = l = r,但是条件为 l<r,直接不会进入循环,同理,在循环内部会发生这样的事情吗?思考吧,
在学习了C++后STL中有两个这样的函数lower_bound ,uppuer_bound;
简单的说lower_bound就是通过二分找到第一个大于或等于val的位置,
uppuer_bound就是通过二分找到第一个大于val的位置,这个val不一定要在数组中
举个例子:
int arr[]={2,3,5,7,11,13,17};
lower_bound(arr,arr+7,3) =2;
lower_bound(arr,arr+7,4) =3; //4并不在数组中
uppuer_bound(arr,arr+7,5) = 4;
uppuer_bound(arr,arr+7,6) = 4; //5并不在数组中
这种函数功能怎么实现呢??
这时候我们就可以回去想想那个l和r会不会有什么用呢?
lower_bound实现
<span style="white-space:pre"> </span>while(l<h)
<span style="white-space:pre"> </span>{
mid = (h+l)/2;
if(arr[mid] == val)//当我们找到值的时候,继续压缩上界,但并不移动(不+1)
h = mid;
else if(arr[mid]<val)//一直保持下界的移动
l = mid+1;
else
h = mid;//这里就不同了,千万别加 1
}
这样我们输出的结果不是mid 而是 left ,我们通过不断的移动下界,达到l = h ,即便找到了val,也有可能有多个重复的在一起,我们无法知道具体哪一个,所以我们用 h=mid压缩上界,直到l=h,这时的 l 就是我们需要的值
upper_bound实现
<span style="white-space:pre"> </span>while(l<h)
{
mid = (h+l)/2;
if(arr[mid] == n)//这里是移动下界,找到了我们就继续往后一位看看,
l = mid +1;
else if(arr[mid]<n)
l = mid+1;
else
h = mid;
}
意会。。。意会。。