二分查找原理很简单,但是边界条件容易出错,出现死循环等,要想彻底分清楚,应该要理解透彻,大家可以用先思考,然后用例子来验证,下面是我的思路,如果有错误,请指正。我们先看变形一:如果有很多待查找的数字,找出最大的,所以最大的一定是在最右边,为了能够把左右两个数进行对比,循环结束的时候,左右指针对应的数要相隔1,所以循环结束的条件left < right -1;要想保留最大下标,当data[mid] == value时,不能结束,因为data[mid+1]也可能等于value,所以要继续遍历,这时让left = mid,不能让right=mid,因为mid右边可能还有等于value的值,所以小于和等于要合并。变形二类似。再看变形三:为了找data[i]<value的最大i,当data[i]==value时也不能结束,此时,由于i肯定是在等于value的那个下标的左边,所以当data[i]==value时,要把right = mid继续遍历,即把大于和等于合并,而此时和变形一不同的时,要找的是小于,而不是等于,所以当data[i]>=value时,结果肯定在i的左边,不可能包括i,所以right = mid -1而不是mid,变形四类似。
标准的二分查找一:
int biSearch(vector<int>& data,int value)
{
int left = 0,right = data.size()-1;//注意1
while(left <= right)//注意2
{
int mid = left + ((right - left) >> 1);//注意3
if(data[mid] < value)left = mid + 1;
else if(data[mid] > value)right = mid - 1;//注意4
else return mid;
}
return -1;
}
标准的二分查找二(不常用):
int biSearch(vector<int>& data,int value)
{
int left = 0,right = data.size();//注意1
while(left < right)//注意2
{
int mid = left + ((right - left) >> 1);
if(data[mid] < value)left = mid + 1;
else if(data[mid] > value)right = mid;//注意3
else return mid;
}
return -1;
}
变形一:如果有多个满足条件,返回序号最大的
int biSearch(vector<int>& data,int value)
{
int left = 0,right = data.size()-1;//注意1
while(left < right - 1)
{
int mid = left + ((right - left) >> 1);
if(data[mid] <= value)left = mid;//注意2
else right = mid;//注意3
}
if(data[right] == value)return right;
if(data[left] == value)return left;
return -1;
}
变形二:如果有多个满足条件,返回序号最小的
int biSearch(vector<int>& data,int value)
{
int left = 0,right = data.size()-1;//注意1
while(left < right - 1)
{
int mid = left + ((right - left) >> 1);
if(data[mid] >= value)right = mid;//注意2
else left = mid;//注意3
}
if(data[left] == value)return left;
if(data[right] == value)return right;
return -1;
}
变形三:求最大的i,使得data[i] < value