二分查找判断条件和边界的选择

二分查找详解


介绍

关于二分查找,也叫折半查找,顾名思义,就是把数据分成两半,将目标值和中间值进行比较,然后决定舍弃左还是右,之后继续缩小范围,但是它有个前提>> 必须是有序 \color{red}{必须是有序} 必须是有序。思路就是这样,一开始以为懂了,但是最后有时写的时候,却发现出现了问题,这是细节没有把握住,没有真正注意到。现在我来说说我的理解,希望能对你有所帮助。


我认为里面最重要的是:

  • while的循环条件

    • 边界的控制

      条件控制

      以left和right为边界来说循环条件一般是:

      • left<=right

          • left< right

        而边界的控制则是每次折半后 l e f t 和 r i g h t 的取值 \color{red}{left和right的取值} leftright的取值
        中间值大于目标值时,目标值在左区间,这时左区间的右边界范围就有不同了
        分别是:

        • right=middle-1

            • right=middle

              • 两个区间不同的就是有没有将中间middle给算进去,而这两个区间搭配两个不同的循环条件,结果 可能会有所不同。当初我学二分时也是大致的看看了,对于right的取值也是不太明白,直到后面出现错误才回头仔细看。

        while(left<=right)

        >>right=middle-1(正确做法)

        int search(int nums[], int size, int target) 
        {
            int left = 0;
            int right = size - 1;	
            while (left <= right) {	//当left == right时
                int middle = (left + right) /2;
                if (nums[middle] > target) {
                    right = middle - 1;	//target在左区间,所以[left, middle - 1]
                } else if (nums[middle] < target) {
                    left = middle + 1;	//target在右区间,所以[middle + 1, right]
                } else {	//相等时
                    return middle;
                }
            }
            //没有找到目标值
            return -1;
        }
        

        >>right=middle(错误做法)

        int search(int nums[], int size, int target)
        {
        	int left = 0;
        	int right = size-1; 
        	while (left <= right) {	
        		int middle = left + ((right - left) / 2);
        		if (nums[middle] > target) {
        			right = middle; //
        		} else if (nums[middle] < target) {
        			left = middle + 1;
        		} else {
        			return middle;
        		}
        	} 
            // 没找到就返回-1
        	return -1;
        }
        
        

        >>图文解释

        我们就来看错误的情况的吧: r i g h t = m i d d l e \color{red}{right=middle} right=middle
        假设找81这个数

        加粗样式
        在这里插入图片描述

        while(left<right)

        >>right=middle(正确写法)

        int search(int nums[], int size, int target)
        {
        	int left = 0;
        	int right = size-1;
        	while (left < right) {	//因为left = right的时候,在[left, right)区间上无意义
        		int middle = left + ((right - left) / 2);
        		if (nums[middle] > target) {
        			right = middle; //target 在左区间,在[left, middle)中 
        		} else if (nums[middle] < target) {
        			left = middle + 1;
        		} else {
        			return middle;
        		}
        	} 
            // 没找到就返回-1
        	return -1;
        }
        
        

        >>right=middle-1(错误做法)

        int search(int nums[], int size, int target)
        {
        	int left = 0;
        	int right = size-1; 
        	while (left < right) {	
        		int middle = left + ((right - left) / 2);
        		if (nums[middle] > target) {
        			right = middle-1; //修改为这个就出问题了
        		} else if (nums[middle] < target) {
        			left = middle + 1;
        		} else {
        			return middle;
        		}
        	} 
            // 没找到就返回-1
        	return -1;
        }
        

        图文解释

        r i g h t = m i d d l e − 1 \color{red}{right=middle-1} right=middle1
        这次的错误是判断条件导致的,可能找的那个数正是left==right时,而此时,却被迫跳出循环,导致错过了要找的数,我们找51试试

        在这里插入图片描述

        在这里插入图片描述
        (7是返回的下标,也就是51的下标),实际上直接出去了,返回了-1

        总结

        对于二分,还有一个,我之前看到,对于它们是左右区间是开还是闭,统一直接用闭区间更加方便,right的初始值就给数组最后一个的下标就行了,这样更容易些,因此我们可以把正确的记下来,我画了个图,来帮助大家记忆
        在这里插入图片描述
        left保持不动
        while和right 要少一起少(少了 = 和 − 1 ),要多一起多(多了 = 和 − 1 ) \color{red}{要少一起少(少了=和-1),要多一起多(多了=和-1)} 要少一起少(少了=1),要多一起多(多了=1
        好了,今天就到这里,希望这些能够帮助你们,共同进步!

        • 2
          点赞
        • 0
          收藏
          觉得还不错? 一键收藏
        • 0
          评论

        “相关推荐”对你有帮助么?

        • 非常没帮助
        • 没帮助
        • 一般
        • 有帮助
        • 非常有帮助
        提交
        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

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

        抵扣说明:

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

        余额充值