二分查找的一些细节问题

二分查找的一些细节问题

  • 更多内容可见二分查找细节详解
  • 首先就是mid的赋值应该写为mid= left+(right-left)/2,这里是为了避免越界。
    并且mid不一定恒为此种写法,因为对于整型计算,1/100是为0的,原因就在于两个int型数据相除其不会四舍五入,即小数部分会被直接去掉,所以这里有可能会陷入一种死循环状态,即mid的值永远不会改变。
  • 这种异常状态在正常的二分查找是不会出现问题的,即:
 while(left<=right)
    {
    
    
        mid = left+(right-left)/2;
        if(res[mid]>target)
        {
    
    
            right = mid-1;
        }
        if(res[mid]<target)
        {
    
    
            left = mid+1;
        }
        if(res[mid]==target)
        {
    
    
            return 1;
        }
    }
  • 正常二分是查找到mid对应元素后立刻return,因此这里即返回的过程是在循环内完成的!!而如果不是left<=right,而是left<right,则最后一次由于区间缩小到了left==right,此时由于没加等号直接退出循环,我们发现此时对应的mid刚好就是left与right相加除以2的结果,即此时该输出的,但是我们让他退出循环了,所以没有成功return,所以这里需要加等号,即left<=right,限制了那种情况下最后一次在循环体内进行return.

  • 但是对于另一种二分查找,即查找的不是target,而是刚好小于target的:

while(left<right)
    {
    
    
        mid = left+(right-left)/2;
        if(letters[mid]>target)
        {
    
    
            right = mid;
        }
        else if(letters[mid]<=target)
        {
    
    
            left = mid+1;
        }
    }
  • 由上述可知,这里由于查找到满足的mid后还要进行验证,因为他不一定是“刚好小于target”,因此我们这里即使查找到了也是当成没有查找到,一直进行循环,直到程序结束,再输出我们最终验证成功的那个。也就是说我们是把找到后输出的过程放在了循环外面,而最后找到后即此时对应left==right,有了此标志后我们已经能判断出此时已经“找到了”,所以直接退出循环返回right或left任意一个即可;

  • 而你若将循环判断条件改为left<=right,则最后找到了的情况还要进行一次循环,这里的话会使得left变了,并没有让left和right都改变,因此这样也是可以的但是最后输出的话必须输出的是right了。

  • 我们发现其与正常二分有些许不同,但是mid的赋值是不变的。 但是当我们要查找刚好比target大的元素时:

 while(left<right)
    {
    
    
        mid = left+(right-left+1)/2;//不多搞1则会卡住
        if(matrix[mid][0]>target)
        {
    
    
            right = mid-1;
        }
        if(matrix[mid][0]<=target)
        {
    
    
            left = mid;
        }
    }
  • 我们发现mid的赋值发生了变化,这是因为当left = 0,right =
    3时,循环一次后由于计算机不会四舍五入导致数值出现误差,以至于mid的值保持不变,而mid不变由于查找的条件,得到left=mid,所以此时陷入了一个恒等式中,即死循环中,所以要加1.(如果加0.5也是不行的,因为都是整型变量,所以最少要加1)。

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/117869433