二分法前提条件:在一个严格递增的序列中找出给定的数字X。
//传入的初值为[0,n-1]
int binarySearch(int a[],int left,int right,int x){ //二分查找
int mid;
while(left<=right){
mid=(right+left)/2;
if(a[mid]==x)return mid;
else if(a[mid]<x)right=mid-1;
else left=mid+1;
}
return -1; //查找不到
}
注意:如果二分上届超过int数据范围的一半,mid=(right+left)/2的等价语句是:mid=left+(right-left)/2;
进一步探讨:求出序列中第一个大于等于X的元素的位置L以及第一个大于X的元素的位置R。
//函数返回第一个大于等于x的元素的位置
int lower_bound(int a[],int left,int right,int x){ //传入的区间是[0,n]
int mid;
while(left<right){
mid=(left+right)/2;
if(a[mid]>=x)right=mid;
else left=mid+1;
}
return left;
}
如果a[mid]>=x,说明第一个大于等于X的元素的位置一定在Mid处或mid的左侧,应该往左子区间[left,right]继续查询,令right=mid;
如果a[mid]<x,说明第一个大于等于X的元素的位置一定在mid的右侧,应往右子区间[mid+1,right]继续查询,令left=mid+1。
进一步探讨:查找第一个大于X的元素的位置
//求序列中第一个大于X的元素的位置
int upper_bound(int a[],int left,int right,int x){
int mid;
while(left<right){
mid=(left+right)/2;
if(a[mid]>x)right=mid;
else left=mid+1;
}
return left;
}
总结发现:lower_bound和upper_bound都是在寻找序列中第一个满足某条件的元素的位置。
继续拓展下去发现:f(x)=x^2再[1,2]范围计算根号2. 实质是寻找在[1,2]范围内,满足f(mid)=mid^2>√2,同时是Mid的范围在10^-5范围之内。 因此x^2单调递增,可以联想到用二分法。
代码如下:
//求f(x)-2=0的根
const double eps=1e-5;
double f(double x){
return x*x;
}
double calSqrt(){
double left=1,right=2,mid;
while(right-left>eps){
mid=(left+right)/2;
if(f(mid)>2){ //此处f(x)的函数可以替换成任意单调递增函数
right=mid;
}else {
left=mid;
}
}
return mid;
}