器→工具, 编程语言

Python标准库之二分查找bisect

钱魏Way · · 11 次浏览

bisect 模块是 Python 标准库中的一个模块,用于在已排序的序列中进行高效的二分查找和插入操作。二分查找是一种用于在有序列表中快速查找元素的算法,bisect 模块通过维护元素的排序状态来支持这种操作。

bisect 模块主要提供以下功能:

  • 查找插入位置:找出一个元素应该插入的位置,以保持列表的排序状态。
  • 插入元素:在合适的位置插入元素,以保持列表的有序性。
  • 查找元素:在有序列表中查找元素的插入位置或索引。

二分算法简介

二分算法(Binary Search Algorithm)是一种高效的查找算法,适用于在有序数组或列表中查找特定元素。二分算法通过不断地将查找范围减半来快速缩小查找范围,其时间复杂度为 (O(\log n)),这使得它比线性查找算法更高效。

二分查找的基本原理

前提条件:二分查找要求数据结构是有序的(通常是从小到大排序)。

查找过程:

  • 初始化三个指针:左指针left指向数组的起始位置,右指针right指向数组的结束位置。
  • 计算中间位置的索引mid,通常为 $(\text{left} + \text{right}) // 2$。
  • 比较中间元素arr[mid]与目标值target:
    • 如果arr[mid]等于target,则查找成功,返回mid。
    • 如果arr[mid]小于target,则目标值在右半部分,将left更新为mid + 1。
    • 如果arr[mid]大于target,则目标值在左半部分,将right更新为mid – 1。
  • 重复以上步骤,直到找到目标值或查找范围为空(即left> right)。

二分查找的实现

以下是Python中二分查找的实现:

def binary_search(arr, target):
    left, right = 0, len(arr) - 1

    while left <= right:
        mid = (left + right) // 2

        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    return -1  # 表示目标值不在数组中

# 示例使用
sorted_array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
target_value = 5
index = binary_search(sorted_array, target_value)
print(f"Element {target_value} found at index {index}")  # 输出: Element 5 found at index 4

二分查找的变种

  • 查找第一个或最后一个出现的位置:在重复元素的情况下,二分查找可以用于查找第一个或最后一个出现的目标值,通过在比较时调整指针的移动方向来实现。
  • 查找插入位置:类似于bisect模块中的bisect_left和bisect_right,可以用于查找元素应该插入的位置以保持数组有序。
  • 查找满足条件的最小/最大值:在一些优化问题中,可以使用二分查找来确定满足某些条件的最小或最大值。

优缺点

优点:

  • 时间复杂度为 (O(\log n)),比线性查找的 (O(n)) 更高效。
  • 简单易于实现现,适用于大多数有序数据结构。

缺点:

  • 仅适用于有序数据结构,需要在使用前对数据进行排序。
  • 不适用于链表等不支持随机访问的数据结构。

二分查找是一个经典且基础的算法,广泛应用于计算机科学的各个领域,特别是在需要快速查找的场景中。

bisect_left、bisect_right

bisect.bisect_left(array, x, lo=0, hi=len(array))

在有序列表 array 中查找 x 应该插入的位置,以保持列表的排序状态。如果 x 已经存在于列表中,返回 x 应该插入的位置,该位置在已存在元素的左侧。

  • array:有序列表。
  • x:要插入的元素。
  • lo:要查找的范围的起始索引(默认为 0)。
  • hi:要查找的范围的结束索引(默认为列表的长度)。
import bisect

arr = [1, 3, 4, 4, 5]
index = bisect.bisect_left(arr, 4)
print(index)  # 输出: 2 (4 应插入在索引 2,即第一个 4 的位置)

bisect.bisect_right(array, x, lo=0, hi=len(array))

在有序列表 array 中查找 x 应该插入的位置,以保持列表的排序状态。如果 x 已经存在于列表中,返回 x 应该插入的位置,该位置在已存在元素的右侧。

  • array:有序列表。
  • x:要插入的元素。
  • lo:要查找的范围的起始索引(默认为 0)。
  • hi:要查找的范围的结束索引(默认为列表的长度)。
import bisect

arr = [1, 3, 4, 4, 5]
index = bisect.bisect_right(arr, 4)
print(index)  # 输出: 4 (4 应插入在索引 4,即第一个 5 的位置)

insort_left、insort_right

bisect.insort_left(array, x, lo=0, hi=len(array))

在有序列表 array 中将 x 插入到合适的位置,以保持列表的排序状态。插入的位置是在 x 的左侧。

  • array:有序列表。
  • x:要插入的元素。
  • lo:要插入的范围的起始索引(默认为 0)。
  • hi:要插入的范围的结束索引(默认为列表的长度)。
import bisect

arr = [1, 3, 4, 5]
bisect.insort_left(arr, 4)
print(arr)  # 输出: [1, 3, 4, 4, 5]

bisect.insort_right(array, x, lo=0, hi=len(array))

在有序列表 array 中将 x 插入到合适的位置,以保持列表的排序状态。插入的位置是在 x 的右侧。

  • array:有序列表。
  • x:要插入的元素。
  • lo:要插入的范围的起始索引(默认为 0)。
  • hi:要插入的范围的结束索引(默认为列表的长度)。
import bisect

arr = [1, 3, 4, 5]
bisect.insort_right(arr, 4)
print(arr)  # 输出: [1, 3, 4, 4, 5]

参考链接:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注