• 一文读懂二分查找(插入)算法


    二分法


    不知道大家有没有玩过一个猜数字的游戏?玩家一给出一个区间和一个数字,由玩家二来猜这个数字,区间会随着玩家二猜的数字发生变化。

    在不考虑表情变化或者别的影响因素时,玩家二要如何去猜这个数字呢?

    下面我们要介绍的,就是这个游戏的万能解法----二分法,也叫做二分查找法


    定义

    二分查找(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是用来在一个有序数组中查找某一元素的算法。

    过程

    以在一个升序数组中查找一个数为例。

    它每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找。

    关键元素

    • 排好序的列表list

    • 左区间left

    • 右区间right

    • 中间点mid

    • 目标值target

    性质

    时间复杂度

    二分查找的最优时间复杂度为 O ( 1 ) O(1) O(1)

    二分查找的平均时间复杂度和最坏时间复杂度均为 O ( l o g n ) O(logn) O(logn) 。因为在二分搜索过程中,算法每次都把查询的区间减半,所以对于一个长度为 n n n的数组,至多会进行 O ( l o g n ) O(logn) O(logn)次查找。

    空间复杂度

    迭代版本的二分查找的空间复杂度为 O ( 1 ) O(1) O(1)

    递归(无尾调用消除)版本的二分查找的空间复杂度为 O ( l o g n ) O(logn) O(logn)


    Tips

    二分法的演变过程如下图所示

    在这里插入图片描述

    通过不断的修正区间,达到找目标值的目的。

    二分查找

    def Bisection(tar):
        weight=[1<<i for i in range(1,10)]
        print("Weight is ",weight)
        l,r=0,len(weight)-1
        
        while l<=r:
            # 确定中心点
            mid=(r-l)//2+l
            # 修改边界
            if weight[mid]==tar:
                # 找到了中心点
                return mid
            if weight[mid]<tar:
                # 目标值在右边
                # 此时需要把区间往右移动
                l=mid+1
            else:
                r=mid-1
        return -1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们来看看输出情况

    print(Bisection(512))
    print(Bisection(127))
    print(Bisection(128))
    print(Bisection(0))
    print(Bisection(513))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    8
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    -1
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    6
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    -1
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    -1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以发现,目标值都被正确的输出了,而不在范围内的值,则是以-1进行输出。


    二分插入

    向右边插入

    这个问题的关键在于,当tar==mid的时候,我们让左区间往右走。于是,当出现相同值的时候,插入位置被修正为右边。

    def Bisection(tar):
        weight=[1<<i for i in range(1,10)]
        print("Weight is ",weight)
        l,r=0,len(weight)-1
    
        while l<=r:
            # 确定中心点
            mid=(r-l)//2+l
            # 修改边界
            if weight[mid]<=tar:
                # 此时需要把左区间往右移动
                l=mid+1
            else:
                r=mid-1
        return l
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    9
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    6
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    7
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    0
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    诶,我们发现,512的插入位置在9号,128的插入位置在7号。

    向左插入

    同理啦,我们只需要在tar==n[mid]的时候,把右区间往左移,从而实现拿到左端点的情况。

    def Bisection(tar):
        weight=[1<<i for i in range(1,10)]
        print("Weight is ",weight)
        l,r=0,len(weight)-1
    
    
        while l<=r:
            # 确定中心点
            mid=(r-l)//2+l
            # 修改边界
            if weight[mid]>=tar:
                # 此时需要把右区间往左移动
                r=mid-1
            else:
                l=mid+1
        return l
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    8
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    6
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    6
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    0
    Weight is  [2, 4, 8, 16, 32, 64, 128, 256, 512]
    9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以看到,512被插入到了8号位,513则被插入到了9号位。

  • 相关阅读:
    第三章:使用Vue脚手架
    数据结构与算法之美09(排序)
    maven编译,本地jar存在确报找不到
    高级架构师_Elasticsearch_第四章_企业级高可用分布式集群
    【递归、搜索与回溯算法】第七节.257. 二叉树的所有路径和46. 全排列
    相机标定基本原理
    数字滤波器分析---零极点分析
    分布式精华笔记!带你深入剖析一致性共识算法还不来看?
    测试大语言模型在嵌入式设备部署的可能性——模型TinyLlama-1.1B-Chat-v1.0
    docker下elasticsearch开启账号密码验证与java集成elasticsearch
  • 原文地址:https://blog.csdn.net/qq_45957458/article/details/127709133