二分查找法(折半查找法)---详细,全面,通俗易懂

1.二分查找法查找某一特定数

  • 关于二分查找最重要的是细节,到底是left < right 还是 left <= right , left = mid 还是left = mid + 1,只要弄明白它的区间是开还是闭,细节自然会一清二楚。
  • 如下代码因为它此刻的右端索引为right = len - 1; right为数组最后一个索引,为左闭右闭区间,[left,right],缩小区间是故应为[left, mid - 1] 和[mid + 1,right],而mid已经被搜索过,则应被删除。
int binarySearch(int arr[], int target, int len)
{
    int left = 0;
    int right = len - 1;//最后一个元素的索引

    while(left <= right)//左闭右闭区间 ->[left,right]
    {
        int mid = left + (right - left) / 2;//为了防止溢出,(right + left ) / 2可能会溢出
        if(arr[mid] == target)
            return mid;//找到指定数就立即返回
        else if(arr[mid] > target)
            right = mid - 1;
        else if(arr[mid] < target)
            left = mid + 1;
        
    }
    return -1;
    
}

2.搜索左边界(两种方法)

  • 若有数组[2,3,5,5,6,7,9],我要获得第一个5的下标,此时index应为2,即为获取左边界!
  • 此时找到符合的数不要立即返回,应继续缩小区间,right = mid。此刻区间为[left,right),缩小区间而mid没有被搜索过,故需要right = mid。
  • while(left < right) 终止的条件是 left == right,此时搜索区间 [left, left) 为空,所以可以正确终止。
int leftBinarySearch(vector<int> &v1, int target)
{
    //主要查看左右区间
    if(v1.size() == 0) return -1;
    int left = 0;
    //此时区间是左闭右开->[left,right)
    int right = v1.size();//right为最后一元素的下一位置,不能取值
    
    while(left < right)//Attention
    {
        int mid = left + (right - left) / 2;
        
        if(v1[mid] == target)
            right = mid;//Attention
        else if(v1[mid] > target)
            right = mid;//Attention
        else if(v1[mid] < target)
            left = mid + 1;
        
    }
    //检查越界或者没有查找元素时
    if(left >= v1.size() || v1[left] != target) return -1;
    
    return left;
  
}

  • 此时为左闭右闭区间,[left,right],判断区间范围,可根据right是否为最后一个元素索引还是最后一个元素的下一个下标。right = v1.size() -->左闭右开区间, right = v1.size() - 1 -->左闭右闭区间。
int leftBinartSearch_1(vector<int> &v1, int target)
{
    if(v1.size() == 0) return -1;
    int left = 0, right = v1.size() - 1;
    
    while(left <= right)//Attention
    {
        int mid = left + (right - left) / 2;
        if(v1[mid] == target)
            right = mid - 1;//Attention
        else if (v1[mid] > target)
            right = mid - 1;//Attention
        else if(v1[mid] < target)
            left = mid + 1;
        
    }
    
    if(left >= v1.size() || v1[left] != target) return -1;
    
    return left;
    
    
    
}


3.搜索右边界(两种方法)

  1. 类似于左边界,不过需要注意return right - 1;因为此刻退出循环时,left = right,v1[left] 一定不等于target了,而v1[left - 1]可能等于target,故需要right - 1。
  2. 若有数组[2,3,5,5,6,7,9],我要获得最后一个5的下标,此时index应为3,即为获取右边界!
int rightBinarySearch(vector<int> &v1, int target)
{
    if(v1.size() == 0) return -1;
    int left = 0, right = v1.size();
    
    while (left < right)
    {
        int mid = left + (right - left) / 2;
        
        if(v1[mid] == target)
            left = mid + 1;
        else if(v1[mid] < target)
            left = mid + 1;
        else if(v1[mid] > target)
            right = mid;
        
    }
    //检查越界或者没有查找元素时
    if(right < 0 || v1[right - 1] != target) return -1;
    
    return right - 1;//退出循环的时 left = right,v1[left] 一定不等于target了,故需要减1
    
    
}


  1. return right;//因为代码中有right - 1,故不需要减1了

int rightBinarySearch_1(vector<int> &v1, int target)
{
    if(v1.size() == 0) return -1;
    int left = 0, right = v1.size() - 1;
    
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        
        if(v1[mid] == target)
            left = mid + 1;
        else if(v1[mid] < target)
            left = mid + 1;
        else if(v1[mid] > target)
            right = mid - 1;
        
    }
    
    if(right < 0 || v1[right] != target) return -1;
    
    return right;//因为代码中有mid - 1,故不需要减1了
}

PS:本文有参考借鉴labuladong大佬所写,大佬写的更加仔细透彻,原文链接如下!
二分查找

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值