Python数据结构9:查找,顺序查找解法,二分查找(和递归算法求解)

1. 顺序查找

查找有顺序查找Sequential Search、二分查找Binary Search等查找方法。在Python中,用下标查找数据项的技术,是顺序查找。

1.1 定义

顺序查找是从列表中的第一个数据项开始。按照下标增长的顺序,逐个比对数据项,如果到最后一个都未发现要查找的项,那么查找失败。

1.2 代码

def sequentialSearch(thelist, item):
    i = 0
    found = False
    pos = 0
    while i < len(thelist) and found == False:
        if thelist[i] == item:
            found = True
            pos = i
        else:
            i = i + 1
    if found:
        return pos
    else:
        return False

print(sequentialSearch([1, 2, 3, 4], 2)) # 1 
print(sequentialSearch([1, 2, 3, 4], 4)) # 3
print(sequentialSearch([1, 2, 3, 4], 5)) # False

1.3 算法分析

算法复杂度是O(n)

- 如果数据项不在列表中,需要比对所有数据项才能得知,比对次数是n - 如果数据项在列表中,最好的情况,第1次比对就找到,最坏的情况,要n次比对

1.4 有序表的顺序查找

当数据项存在时,查找有序表和无序表的方法完全相同。但是当数据项不在表中时,有序表可以提前结束。

查找数据项50,当看到54时,可知道后面不可能存在50,可以提前退出查找。

def sequentialSearch(thelist, item):
    found = False
    stop = False
    i = 0
    while i < len(thelist) and not found and not stop:
        if thelist[i] != item:
            i = i + 1
        elif thelist[i] > item:
            stop = True
        else:
            found = True
    return found

print(sequentialSearch([1, 3, 5, 7], 4)) # False
print(sequentialSearch([1, 3, 5, 7], 5)) # True
print(sequentialSearch([1, 3, 5, 7], 8)) # False

算法复杂度仍然是O(n), 只是在数据项不存在的时候,有序表的查找能节省一些比对次数,但并不改变其数量级。

2. 二分查找(折半查找)法

2.1 定义

二分法利用有序表的特性,缩小待比对数据项的范围。从列表中间开始比对,如果列表中间的项匹配查找项,则查找结束如果不匹配,那么就有两种情况:

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

无论如何,我们都会将比对范围缩小到原来的一半:n/2
继续采用上面的方法查找,每次都会将比对范围缩小一半

2.2 代码

def binarySearch(thelist, item):
    found = False
    first = 0
    last = len(thelist) - 1
    position = 0
    while first <= last and not found:
        midpoint = (first + last) // 2 # // 是除法取整数
        if item > thelist[midpoint]:
            first = midpoint + 1
        elif item < thelist[midpoint]:
            last = midpoint - 1
        elif item == thelist[midpoint]:
            found = True
            position = midpoint
    if found == True:
        return position
    else:
        return False
print(binarySearch([1, 3, 5, 7, 9], 5)) 
print(binarySearch([1, 3, 5, 7, 9], 2))
print(binarySearch([1, 3, 5, 7, 9], 7))
print(binarySearch([1, 3, 5, 7, 9], 3))
print(binarySearch([1, 3, 5, 7, 9], 8))

2.3 分而治之,递归解法

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

  • 将问题分为若干更小规模的部分
  • 通过解决每一个小规模部分问题,并将结果汇总得到原问题的解

递归算法求解:

def binary_search(the_list, item):
    mid = len(the_list) // 2
    if the_list[mid] == item:
        return mid
    # 基本结束条件
    if the_list[mid] > item:
        return binary_search(the_list[0: mid], item)
    if the_list[mid] < item:
        return mid + binary_search(the_list[mid:], item)
    # 向小规模前进
    # 调用自身


print(binary_search([1, 3, 5, 7, 9], 1))
print(binary_search([1, 3, 5, 7, 9], 3))
print(binary_search([1, 3, 5, 7, 9], 5))

2.4 算法分析

由于二分查找,每次比对都将下一步的比对范围缩小一半
每次比对后剩余数据项如下表所示:

当比对次数足够多以后,比对范围内就会仅剩余1个数据项 n / 2 ^ i = 1 i = log_2 n 二分法查找的算法复杂度是O(log n)

另外,虽然二分查找在时间复杂度上优于顺序查找,但也要考虑到对数据项进行排序的开销。换句话说,二分查找需要先排序,会更麻烦一点。

参考文献

本文的知识来源于B站视频 【慕课+课堂实录】数据结构与算法Python版-北京大学-陈斌-字幕校对-【完结!】,是对陈斌老师课程的复习总结。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值