编程语言
首页 > 编程语言> > 二分查找——没有想象中的容易(详解各种变式,超深度理解,c++)

二分查找——没有想象中的容易(详解各种变式,超深度理解,c++)

作者:互联网

int binarySearch(int[] nums, int target) {
    int left = 0; 
    int right = nums.length - 1; // 注意

    while(left <= right) {
        //int mid = (right + left) / 2;  //不建议使用
           int mid = left + (right-left)/2;
        if(nums[mid] == target)
            return mid; 
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid - 1; // 注意
        }
    return -1;
}

这就是最基本的二分查找,若查找成功,则立即返回target下标mid,否则返回-1

老生常谈的细节:

(1)mid = left + (right-left)/2 , 之所以这样写,避免了right与left相加除以2,分子相加时可能超过INT_MAX范围的问题

(2)right = 数组长度-1 时,while中一定对应的是left<=right , 因为每次搜索都是在[left, right]闭区间上,只有left!=right 才会停止查找

(3)建议先判断一下数组是否为空(empty)

(4)不存在target时,一定返回-1

(5)理解一下mid = left + (right-left)/2 总是返回中间数偏向于left的一侧(自己理解一下,有用)

 

然后,就是变式

如果我一定要写成:right = 数组长度呢?我怎么修改代码呢?(这就是为什么网上会有两种模板)

模板如下,改动地方有三个:

1. right = 数组长度(不要减一)

 2.while判断条件是 left<right(而不是left<=right)

3. right = m(不是right = mid +1)

 1 int main()
 2 {
 3     vector<int> v={1,2,3,4,5,6,7};
 4     int key = 9,index=-1;
 5     int l=0,r=v.size();
 6     while(l<r)
 7     {
 8         int m =l+(r-l)/2;
 9         if(v[m]==key)
10         {
11             index = m;
12             break;
13         }
14         else if(v[m]<key)
15             l = m+1;
16         else
17             r = m;
18     }
19     cout<<"index:"<<index<<endl;
20     return 0;
21 }

第二份代码和第一份效果一模一样,如何理解呢?

第二份中,r设定为数组长度,所以搜索空间是[left, right) , 当left==right时,就已经可以退出了,所以while中写left<right。如果mid值与key值不相等,那么由于mid值已经搜索过了,

所以下次检索时,是从[left,mid) 或 [mid+1,right) 开始,所以写成了right = mid(而不是right = mid +1)

 

继续变式:

(1)想要返回第一个等于key的下标,如{1,2,3,3,3,4}中,key=3,则返回下标

find_first_equal

 1 int find_first_equal(vector<int> v, int key)
 2 {
 3     int l=0, r =v.size()-1;
 4     int index;
 5     while(l<=r)
 6     {
 7         int m = l+(r-l)/2;
 8         if(v[m]>=key)
 9             r = m-1;
10         else
11             l = m+1;
12     }
13     if(l>=0&&l<=v.size()-1&&v[l]==key)
14         index = l;
15     else
16         index = -1;
17     cout<<"find_first_equal,index:"<<index<<endl;
18     return index;
19 }

技术关键点在于:

第一,退出的时候,我们要的是left还是right,想一想。

第二,如果key值不存在,那么left可能不合法,所以要判断left在正常范围内,并且要和key对上。

 

(2)想要返回最后一个等于key的下标,如{1,2,3,3,3,4}中,key=3,则返回下标4

find_final_equal

 1 int find_final_equal(vector<int> v, int key)
 2 {
 3     int l=0, r =v.size()-1;
 4     int index;
 5     while(l<=r)
 6     {
 7         int m = l+(r-l)/2;
 8         if(v[m]<=key)
 9             l = m+1;
10         else
11             r = m-1;
12     }
13     if(r>=0&&r<=v.size()-1&&v[r]==key)
14         index = r;
15     else
16         index = -1;
17     cout<<"find_final_equal,index:"<<index<<endl;
18     return index;
19 }

(3)想要返回第一个大于key的下标,如{1,2,3,4,5}中,key=3,则返回下标3

find_first_bigger

 1 int find_first_bigger(vector<int> v, int key)
 2 {
 3     int l=0, r =v.size()-1;
 4     int index;
 5     while(l<=r)
 6     {
 7         int m = l+(r-l)/2;
 8         if(v[m]<=key)
 9             l = m+1;
10         else
11             r = m-1;
12 
13     }
14     if(l<=v.size()-1)
15          index = l;
16     else
17         index = -1;
18     cout<<"find_first_bigger,index:"<<index<<endl;
19     return index;
20 }

参考文档:

1.https://blog.csdn.net/asmartkiller/article/details/96179338

2.https://www.cnblogs.com/luoxn28/p/5767571.html

标签:right,变式,int,mid,c++,while,详解,key,left
来源: https://www.cnblogs.com/qiezi-online/p/12932252.html