数据结构与算法(Python版)三十二:二分查找算法及分析

二分查找

那么对于有序表, 有没有更好更快的查找算法?

在顺序查找中, 如果第1个数据项不匹配查找项的话, 那最多还有n-1个待比对的数据项

那么, 有没有方法能利用有序表的特性,迅速缩小待比对数据项的范围呢?

我们从列表中间开始比对!

如果列表中间的项匹配查找项,则查找结束
如果不匹配,那么就有两种情况:

  • 列表中间项比查找项大,那么查找项只可能出现在前半部分
  • 列表中间项比查找项小,那么查找项只可能出现在后半部分

无论如何,我们都会将比对范围缩小到原来的一半: n/2
在这里插入图片描述

继续采用上面的方法查找

每次都会将比对范围缩小一半

二分查找:代码

def binarySearch(alist, item):
    first = 0
    last = len(alist)-1
    found = False

    while first<=last and not found:
        midpoint = (first+last)//2
        if alist[midpoint] == item:
            found = True
        else:
            if item < alist[midpoint]:
                last = midpoint-1
            else:
                first = midpoint+1

    return found

testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))

二分查找:分而治之

二分查找算法实际上体现了解决问题的典型策略: 分而治之

将问题分为若干更小规模的部分通过解决每一个小规模部分问题,并将结果汇总得到原问题的解
在这里插入图片描述

显然, 递归算法就是一种典型的分治策略算法, 二分法也适合用递归算法来实现

def binarySearch(alist, item):
    if len(alist) == 0:
        return False
    else:
        midpoint = len(alist)//2
        if alist[midpoint]==item:
            return True
        else:
            if item < alist[midpoint]:
                return binarySearch(alist[:midpoint], item)
            else:
                return binarySearch(alist[midpoint+1:], item)

testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))

二分查找:算法分析

由于二分查找, 每次比对都将下一步的比对范围缩小一半

每次比对后剩余数据项如下表所示:

在这里插入图片描述

当比对次数足够多以后, 比对范围内就会仅剩余1个数据项

无论这个数据项是否匹配查找项, 比对最终都会结束, 解下列方程:

在这里插入图片描述

所以二分法查找的算法复杂度是O(log n)

虽然我们根据比对的次数, 得出二分查找的复杂度O(log n)

但本算法中除了比对, 还有一个因素需要注意到:

binarySearch(alist[:midpoint],item)
这个递归调用使用了列表切片,而切片操作的复杂度是O(k),这样会使整个算法的时间复杂度稍有增加;当然,我们采用切片是为了程序可读性更好,实际上也可以不切片,而只是传入起始和结束的索引值即可,这样就不会有切片的时间开销了。

二分查找:进一步的考虑

另外, 虽然二分查找在时间复杂度上优于顺序查找

但也要考虑到对数据项进行排序的开销

如果一次排序后可以进行多次查找,那么排序的开销就可以摊薄,但如果数据集经常变动,查找次数相对较少,那么可能还是直接用无序表加上顺序查找来得经济

所以, 在算法选择的问题上, 光看时间复杂度的优劣是不够的, 还需要考虑到实际应用的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值