《二分查找,你真的会吗?》---代码八问

本文详细解析了二分查找的五个扩展问题,包括如何在数组中查找特定元素及其各种情况下的实现方法,并深入分析了每种方法背后的原理。通过问题一到问题五的探讨,读者可以全面理解二分查找的灵活性和应用范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.网友代码

二分查找或其扩展的问题及对应程序,内容如下:

1)二分查找元素key的下标,如无 return -1

2)二分查找返回key(可能有重复)第一次出现的下标,如无return -1

3)二分查找返回key(可能有重复)最后一次出现的下标,如无return -1

4)二分查找返回刚好小于key的元素下标,如无return -1

5)二分查找返回刚好大于key的元素下标,如无return -1

直接上代码:

/* binsearch 寻找key下标,不存在 return -1 */
int binsearch(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left <= right)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] < key)
        {
            left = mid + 1;
        }else if(arr[mid] > key)
        {
            right = mid - 1;
        }else
            return mid;
    }
    return -1;
}
 
/* binsearch_min 返回key(可能有重复)第一次出现的下标,如无return -1 */
int binsearch_min(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] < key)
        {
            left = mid+1;
        }else
        {
            right = mid;
        }
    }
    if(arr[left] == key)    return left;//在退出循环的越界区间[right,left]考虑此处为什么用left
    return -1;
}
 
/* binsearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1 */
int binsearch_max(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right -1)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] <= key)
        {
            left = mid;
        }else
        {
            right = mid-1;
        }
    }
    if(arr[right] == key) // 找max,先判断right
    {
        return right;
    }else if(arr[left] == key)
    {
        return left;
    }else
        return -1;
}
 
/* binsearch_justsmall 返回刚好小于key的元素下标,如无return -1 */
int binsearch_justsmall(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right - 1)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] < key)
        {
            left = mid;
        }else
        {
            right = mid - 1;
        }
    }
    if(arr[right] < key) // 找刚好小于,先判断right
    {
        return right;
    }else if(arr[left] < key)
    {
        return left;
    }else
        return -1;
}
 
/* binsearch_justgreat 返回刚好大于key的元素下标,如无return -1 */
int binsearch_justgreat(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] <= key)
        {
            left = mid + 1;
        }else
        {
            right = mid;
        }
    }
    if(arr[right] > key) return right;//在退出循环的越界区间[right,left]上考虑此处为什么用right
    return -1;}

对应的测试程序及结果请参考《二分查找,你真的会吗?》 


2.二分代码原理分析

下面是本篇文章的重点,即以上所列二分查找代码原理细节思考:

1.为什么问题一的解法中while条件为小于等于?
从问题结果出发考虑,因为问题一需要找到等于K的位置,否则返回-1;而其他四个问题需要找到模糊位置,所以while条件中不能加等于条件;

2.为什么当解法中while条件为left<right时结果只用判断一个,而为left<right-1时需要判断两个呢?
因为当为left<right时,退出循环后区间[left,right]中只有一个元素;而为left<right-1时,退出循环后区间[left,right]中有两个元素;

3.为什么当寻找关于min的解法中while条件下不能使用if(arr[mid]<=key){ left=mid; }呢?
从问题结果出发考虑,因为此时如果mid左边还有等于K的值时,left不能移动回去,因为每次left都是只增不减,导致寻找最小值时左边边界确定失败。因此需要使用if(arr[mid]<key){ left=mid+1; }来确定准确的左边边界。

4.为什么当寻找关于max的解法中while条件下使用if(arr[mid]<=key){ left=mid; }呢?
从问题结果出发考虑,因为此时寻找的是最大的位置,此时如果arr[mid]等于key,则最大位置肯定包含在区间[mid,end)之间,如果使用left=mid+1同时left又是最后一个匹配的位置的时候,则导致寻找最大值时左边边界确定失败。因此需要使用if(arr[mid]<=key){ left=mid+1; }来确定准确的左边边界。

5.为什么当寻找关于max的解法中while条件使用left<right-1呢?
从if条件出发考虑,因为下面左边界的定位使用if(arr[mid]<=key){ left=mid; },导致当有两个元素的时候每次left可能无变化,这样在计算mid的时候值也无变化导致死循环。为了解决这个问题,使用left<right-1,判断区间[left,right]中是否还剩两个元素来避免死循环。


6.为什么问题二和问题四的解法中while条件及中间代码一样,但是最后先比较的对象不同呢?
从问题结果出发考虑,因为问题二要找等于K的最小位置,从右半边过来的right表示[right,end]都满足大于等于K,此时如果left越界处于[right,end],则根据循环条件退出,此时left所指向的位置刚好是第一个等于K的位置。

7.为什么当寻找关于min、justgreate时解法中while条件为left<right,而寻找max、justsmalll时解法中while条件为left<right-1呢?
从while下if条件是否导致死循环出发考虑,因为寻找关于min、justgreate时解法中if条件不会导致死循环,所以while条件为lef<right;而寻找max、justsmalll时解法中if条件会导致死循环,所以while条件为lef<right-1来避免;

8.整个二分查找的五个扩展问题解决思路所遵循的原则是什么?(总结)
1)先从最终结果的区间出发来考虑if语句中的写法;

2)先从while下的if条件是否会导致死循环出发来考虑while条件;(考虑只有两个元素的情况)

3)先从找min思考来推出max的解法;


3.参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值