如何利用Python实现二分查找(迭代和递归)

简介: 如何利用Python实现二分查找(迭代和递归)

“Although the basic idea of binary search is comparatively  straightforward, the details can be surprisingly tricky, and many good  programmers have done it wrong the first few times they tried.”

— Donald Knuth

翻译:虽然二分查找的基本思想相对简单,但细节可能会非常棘手,许多优秀的程序员在最开始的尝试中都做错了。

 二分查找 Binary Search

算法思想:二分查找用于在一个含有n个元素的有序序列中有效地定位目标值

考虑一下三种情况:

  • 如果目标值 value == [middle]的数据,查找成功并且终止
  • 如果目标值 value > [middle]的数据,对后半部分序列重复这一过程,即索引的范围从mid + 1right
  • 如果目标值 value < [middle]的数据,对前半部分序列重复这一过程,即索引的范围从leftmiddle - 1

迭代定义 - Iteratively

# binary_search.py
def binary_search_iterative(elements, value):
    left, right = 0, len(elements)-1
    while left <= right:
        middle = (left + right) // 2
        if elements[middle] == value:
            return middle
        elif elements[middle] < value:
            left = middle + 1
        else:
            right = middle - 1
    return None
if __name__ == '__main__':
    nums = [1, 2, 3, 4, 5]
    print(binary_search_iterative(nums, 2))  # Output: 1,值为2的元素出现在索引1的位置(索引从0开始)
    print(binary_search_iterative(nums, 10))  # Output: None,表示空,没有找到指定的元素

 递归定义 - Recursively

第一版

类似二分查找的迭代版本,使用切片运算符:将列表切碎:

def binary_search_recursive(elements, value):
    if len(elements) == 0:
        return False
    left, right = 0, len(elements) - 1
    if left <= right:
        middle = (left + right) // 2
        if elements[middle] == value:
            return True
        elif elements[middle] < value:
            return binary_search_recursive(elements[middle+1:], value)
        else:
            return binary_search_recursive(elements[:middle], value)
    return False
if __name__ == '__main__':
    nums = [1, 2, 3, 4, 5]
    print(binary_search_recursive(nums, 2))  # True
    print(binary_search_recursive(nums, 10))  # False

不用像迭代那样使用while循环,只需检查一下条件。在对应的分片列表中调用相同的函数。

使用分片会有什么问题?好吧,事实证明,切片会生成元素引用的副本,这些副本可能具有显着的内存和计算开销。

第2版

为避免复制操作,您可以重复使用相同的列表,但在必要时将不同的边界传递给函数

def binary_search(elements, value, left, right):
    if left <= right:
        middle = (left + right) // 2
        if elements[middle] == value:
            return True
        elif elements[middle] < value:
            return binary_search(elements, value, middle+1, right)
        else:
            return binary_search(elements, value, left, middle-1)
    return False
if __name__ == '__main__':
    nums = [1, 2, 3, 4, 5]
    print(binary_search(nums, 2, 0, len(nums)-1)) # True
    print(binary_search(nums, 10, 0, len(nums)-1))  # False

缺点是每次您要调用该函数时,都必须传递初始边界,以确保它们正确无误:binary_search(nums, 10, 0, len(nums)-1)

第3版

更进一步,您可能希望将一个函数嵌套在另一个函数中以隐藏技术细节并利用外部作用域中的变量重用:

def contains(elements, value):
    def recursive(left, right):
        if left <= right:
            midddle = (left + right) // 2
            if elements[midddle] == value:
                return True
            elif elements[midddle] < value:
                return recursive(midddle+1, right)
            else:
                return recursive(left, midddle-1)
        return False
    return recursive(0, len(elements) - 1)
if __name__ == '__main__':
    nums = [1, 2, 3, 4, 5]
  print(contains(nums, 2))  # True
    print(contains(nums, 10))  # False

即使在封闭范围内定义了recursive()内部函数,也可以访问元素和值参数。

迭代和递归实现之间的选择通常是性能考虑,便利性以及个人喜好的最终结果。

 总结

本文中介绍了首先二分查找的基本思想,然后用迭代和递归两种方法实现了简易版的二分查找,其实Python实现了功能更强大的二分查找的库 bisect,感兴趣的同学,可以在本文的基础上进行学习。

最后:二分查找的时间复杂度:O(log(n))

推荐阅读:

How to Do a Binary Search in Python


相关文章
|
Python
二分查找变种大赏!Python 中那些让你效率翻倍的搜索绝技!
二分查找是一种高效的搜索算法,适用于有序数组。其基本原理是通过不断比较中间元素来缩小搜索范围,从而快速找到目标值。常见的变种包括查找第一个等于目标值的元素、最后一个等于目标值的元素、第一个大于等于目标值的元素等。这些变种在实际应用中能够显著提高搜索效率,适用于各种复杂场景。
175 9
|
算法 数据处理 开发者
超越传统:Python二分查找的变种策略,让搜索效率再上新台阶!
本文介绍了二分查找及其几种Python实现的变种策略,包括经典二分查找、查找第一个等于给定值的元素、查找最后一个等于给定值的元素以及旋转有序数组的搜索。通过调整搜索条件和边界处理,这些变种策略能够适应更复杂的搜索场景,提升搜索效率和应用灵活性。
146 5
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
261 2
|
Python
【10月更文挑战第18天】「Mac上学Python 29」基础篇10 - 循环结构与迭代控制
在Python中,循环结构是控制程序执行的重要工具。通过学习本篇内容,您将掌握如何使用for循环和while循环来高效地处理重复任务,并了解break、continue和else的使用方式。同时,我们还会探索嵌套循环和典型应用场景中的实际应用。
205 2
|
Java 程序员 C++
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
160 0
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
|
算法 Python
python函数递归和生成器
python函数递归和生成器
|
存储 大数据 数据处理
理解Python中的生成器:高效迭代的秘密
【10月更文挑战第8天】理解Python中的生成器:高效迭代的秘密
112 0
|
算法 数据挖掘 Python
深入理解Python中的递归文件夹读取操作
【8月更文挑战第27天】
309 1
|
存储 安全 数据库
Python中的可迭代性与迭代器
在Python中,可迭代性和迭代器是非常重要的概念,它们为我们提供了一种优雅且高效的方式来处理序列和集合数据。本文将深入探讨这些概念,包括可迭代协议以及与异步编程相关的可迭代性和迭代器。

推荐镜像

更多