二分查找变形记:从循环不变量说起

本文介绍了二分查找的基本原理及其与循环不变量的关系。通过循环不变量来证明二分查找算法的正确性,并展示了如何利用循环不变量分析不同二分查找变种的正确性。同时,给出了有序数组中查找目标元素的各种情况,包括存在重复元素时的处理方法。
摘要由CSDN通过智能技术生成

二分查找

首选我们介绍标题中提到的两个名词:

二分查找

二分查找的搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则查找成功;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

循环不变量

其主要用来帮助理解算法的正确性。形式上很类似与数学归纳法,它是一个需要保证正确断言。对于循环不变式,必须证明它的三个性质:

  • 初始化:它在循环的第一轮迭代开始之前,应该是正确的。
  • 保持:如果在循环的某一次迭代开始之前它是正确的,那么,在下一次迭代开始之前,它也应该保持正确。
  • 终止:循环能够终止,并且可以得到期望的结果,不变式给了我们一个有用的性质,那就是获得正确的结果。

那这两个东西又有什么关联呢?上面已经提到循环不变量可以证明算法的正确性!这样的话,我们下面就运用循环不变量证明一下二分查找各种应用算法的正确性。

  1. 给定一个有序(升序,我们后面所有提到的数据均为升序,后面不再赘述)数组A,求任意一个i使得A[i]等于target,不存在则返回-1
    这是最原始的二分查找,利用数组有序性进行折半查找,时间复杂度为O(nlogn)。设原始数据为A[0 ~ n-1]

    • 初始化:low = 0, high = n - 1,mid = low + (high - low)/2。如果targer存在原始数组中,其对应index一定处于[low, high], 即 A[low] <= target <= A[high]
    • 保持: 对于 A[mid] <target,则index只能存在[mid + 1, high]中,且low = mid + 1;对于 A[mid] > target, 则index只能存在[low, mid - 1], 且high = mid;对于A[mid] = target,因为 low <= mid <= high, index = mid,直接返回。
    • 终止:low >high(即high + 1)。待处理数组为空,表示tartget不存在此数组中。
    int search(int A[], int n, int target)  
    {  
        int low = 0, high = n-1;  
        while(low <= high)  
        {  
            // 注意:若使用(low+high)/2求中间位置容易溢出  
            int mid = low+((high-low)>>1);   
            if(A[mid] == target)  
                return mid;  
            else if(A[mid] < target)  
                low = mid+1;  
            else // A[mid] > target  
                high = mid-1;  
            // 循环不变式: A[low - 1] < target < A[high + 1]
        }  
        return -1;  
    }

    后面的案例,也都可以按照上述方法证明算法的正确性,但我们不一一赘述,但在描述算法的时候,我们会指出,循环过程中不变的性质(虽然这个性质可能在初始化的时候不一定成立),这对我们理解算法为何这么写有很大帮助!

  2. 给定一个有序数组A,可含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1

    // 两种写法
    int lowerBound(int A[], int n, int target) {
        int low = 0, right = n - 1;
        while(low <= high) {
        /*
        为什么上面一定是 low <= high? low < high 行不行?
        */
            int mid = low + (high - low)/2;
            if(A[mid] < target) low = mid + 1;
            else high = mid - 1;
        }
        /*
        循环过程中,当low大于0时,因为A[mid] < target时,low=mid+1, 所以A[low-1] < target;
        当high小于n-1时,因为A[mid] >= target时,high = mid  - 1, A[high + 1 >= target;
        循环结束时,low 等于 high + 1,所以,如果A[low](A[high + 1])存在就等于target, 
        那么low(high)就是target出现的最小位置,否则target在数组中不存在。 
        综上所示,循环不变式为:  A[low - 1] < target <= A[high + 1]
        */   
        if(low < n && A[low] == target) return low;
        return -1;
    }
    
    int searchFirstPos(int A[], int n, int target)  
    {  
        if(n <= 0) return -1;  
        int low = 0, high = n-1;  
        while(low < high)  
        {  
            int mid = low+((high-low)>>1);  
            if(A[mid] < target)  
                low = mid+1;  
            else // A[mid] >= target  
                high = mid;  
        }  
        /*  
        循环过程中,当low大于0时,因为A[mid] < target时,low=mid+1, 所以A[low-1] < target;
        当high小于等于n-1时,因为A[mid] >= target时,high = mid, A[high] >= target;
        循环结束时,low 等于 high,所以,如果A[low](A[high])就等于target, 
        那么low(high)就是target出现的最小位置,否则target在数组中不存在。 
        综上所示,循环不变式为:  A[low - 1] < target <= A[high]
        */   
        if(A[low] != target)  
            return -1;  
        else  
            
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Matlab中,可以使用二分查找法来查找数组中的元素。以下是使用递归实现的二分查找算法的示例代码: ```matlab function BinarySearch_2(array, low, high, value) n = length(array); if low > high fprintf('Sorry, the number does not exist !!! \n\n') else mid = floor((low + high) / 2); if array(mid) == value fprintf('The number is found at position %d. \n\n', mid); elseif array(mid) < value BinarySearch_2(array, mid + 1, high, value); else BinarySearch_2(array, low, mid - 1, value); end end end % 测试数组 BinarySearch_2([1 3 4 6 8 10 13 21 23 46 54 56], 1, 12, 21); ``` 以上代码实现了一个二分查找函数`BinarySearch_2`,接受一个有序数组、数组的下界、上界和要查找的值作为输入。函数会在数组中查找指定的值,并返回它的位置。如果值不存在于数组中,会输出提示信息。 请注意,这只是一个示例代码,你可以根据自己的需求进行修改和扩展。 另外,除了二分查找,Matlab还提供了其他查找方法,比如线性查找、插值查找等。你可以根据具体情况选择合适的查找算法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [二分查找法及其四种变形(MATLAB)](https://blog.csdn.net/HuiningM/article/details/100173538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Matlab中顺序查找、二分搜索及一二三次样条的一些总结](https://blog.csdn.net/m0_62961080/article/details/121879268)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值