”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 在 Python 中使用排序列表:“bisect”模块的魔力

在 Python 中使用排序列表:“bisect”模块的魔力

发布于2024-08-28
浏览:101

Working with Sorted Lists in Python: Magic of the `bisect` Module

使用排序列表有时可能有点棘手。您需要在每次插入后维护列表的顺序并有效地搜索其中的元素。二分搜索是一种用于在排序列表中搜索的强大算法。虽然从头开始实施并不太困难,但可能非常耗时。幸运的是,Python 提供了 bisect 模块,这使得处理排序列表变得更加容易。

什么是二分查找?

二分搜索是一种在排序数组中查找目标值位置的算法。想象一下您正在电话簿中搜索一个名字。您可能不是从第一页开始,而是从书的中间开始,并根据名称按字母顺序是大于还是小于中间的名称来决定是在前半部分还是后半部分继续搜索。二分查找以类似的方式进行操作:它以两个指针开始,一个位于列表的开头,另一个位于列表的末尾。然后计算中间元素并与目标进行比较。

bisect 模块:简化排序列表操作

虽然二分查找很有效,但每次都写出实现可能很乏味。但是,如果您只需一行代码即可执行相同的操作呢?这就是 Python 的 bisect 模块的用武之地。bisect 是 Python 标准库的一部分,可帮助您维护排序列表,而无需在每次插入后对其进行排序。它使用简单的二分算法来实现这一点。

bisect 模块提供两个关键函数:bisect 和 insort。 bisect 函数查找应插入元素以保持列表排序的索引,而 insort 则将元素插入到列表中同时保持其排序顺序。

使用二等分模块:一个实际示例

让我们从导入模块开始:

import bisect
示例 1:将数字插入排序列表

假设我们有一个已排序的数字列表:

data = [1, 3, 5, 6, 8]

要在保持列表排序的同时插入新数字,只需使用:

bisect.insort(data, 7)

运行此代码后,数据将如下所示:

[1, 3, 5, 6, 7, 8]
示例 2:查找插入点

如果您只想找出数字将插入的位置而不实际插入数字怎么办?您可以使用 bisect_left 或 bisect_right 函数:

index = bisect.bisect_left(data, 4)
print(index)  # Output: 2

这告诉我们应该将数字 4 插入到索引 2 处以保持列表排序。

示例 3:维护动态列表中的排序顺序

假设您正在管理一个动态增长的列表,需要插入元素,同时确保其保持排序:

dynamic_data = []
for number in [10, 3, 7, 5, 8, 2]:
    bisect.insort(dynamic_data, number)
    print(dynamic_data)

这将在插入元素时输出每一步的列表:

[10]
[3, 10]
[3, 7, 10]
[3, 5, 7, 10]
[3, 5, 7, 8, 10]
[2, 3, 5, 7, 8, 10]
示例 4:将 bisect 与自定义对象结合使用

假设您有一个自定义对象列表,例如元组,并且您想根据特定条件插入它们:

items = [(1, 'apple'), (3, 'cherry'), (5, 'date')]
bisect.insort(items, (2, 'banana'))
print(items)  # Output: [(1, 'apple'), (2, 'banana'), (3, 'cherry'), (5, 'date')]

或者您可能想根据每个元组的第二个元素插入:

items = [('a', 10), ('b', 20), ('c', 30)]
bisect.insort(items, ('d', 25), key=lambda x: x[1])
print(items)  # Output: [('a', 10), ('b', 20), ('d', 25), ('c', 30)]

行动中的二分法:搜索单词

二等分模块不限于数字;它对于搜索字符串、元组、字符等列表也很有用。
例如,要在排序列表中查找单词:

def searchWord(dictionary, target):
    return bisect.bisect_left(dictionary, target)


dictionary = ['alphabet', 'bear', 'car', 'density', 'epic', 'fear', 'guitar', 'happiness', 'ice', 'joke']
target = 'guitar'

或者查找具有特定前缀的单词组中的第一个单词:

def searchPrefix(dictionary, prefix):
    return bisect.bisect_left(dictionary, prefix), bisect.bisect_right(dictionary, prefix   'z') # adding 'z' to the prefix to get the last word starting with the prefix
# bisect_rigth function will be discussed in a moment


dictionary = ['alphabet', 'bear', 'car', 'density', 'epic', 'fear', 'generator', 'genetic', 'genius', 'gentlemen', 'guitar', 'happiness', 'ice', 'joke']
prefix = 'gen'

但是,请记住 bisect_left 返回应插入目标的索引,而不是目标是否存在于列表中。

bisect 和 insort 的变体

该模块还包括右侧变体:bisect_right 和 insort_right。如果元素已在列表中,这些函数将返回插入元素的最右侧索引。例如,如果目标在列表中,bisect_right 将返回大于目标的第一个元素的索引,而 insort_right 在该位置插入元素。

引擎盖下平分

bisect 模块的强大之处在于它有效地实现了二分搜索算法。例如,当您调用 bisect.bisect_left 时,该函数实质上对列表执行二分搜索以确定新元素的正确插入点。

下面是它的工作原理:

  1. 初始化:函数以两个指针lo和hi开始,分别代表列表内搜索范围的下限和上限。最初,lo 设置为列表的开头(索引 0),hi 设置为列表的末尾(索引等于列表的长度)。但您也可以指定自定义 lo 和 hi 值以在列表的特定范围内进行搜索。

  2. Bisection:在循环内,该函数计算 lo 和 hi 之间的中点 (mid)。然后它将中间的值与您要插入的目标值进行比较。

  3. 比较:

* If the target is less than or equal to the value at `mid`, the upper bound (`hi`) is moved to `mid`.
* If the target is greater, the lower bound (`lo`) is moved to `mid   1`.
  1. 终止:这个过程继续进行,每次将搜索范围减半,直到lo等于hi。此时,lo(或 hi)表示应将目标插入其中以维持列表排序顺序的正确索引。

  2. 插入:对于 insort 函数,一旦使用 bisect_left 找到正确的索引,目标就会被插入到列表中的该位置。

这种方法确保插入过程高效,由于列表移位操作,搜索的时间复杂度为 O(log n),插入的时间复杂度为 O(n)。这比每次插入后对列表进行排序要高效得多,特别是对于大型数据集。

bisect_left 代码示例:

    if lo 



insort_left 代码示例:

def insort_left(a, x, lo=0, hi=None, *, key=None):

    if key is None:
        lo = bisect_left(a, x, lo, hi)
    else:
        lo = bisect_left(a, key(x), lo, hi, key=key)
    a.insert(lo, x)

结论

bisect 模块使排序列表的处理变得简单而高效。下次您需要执行二分搜索或将元素插入排序列表时,请记住二等分模块,这样可以节省时间和精力。

版本声明 本文转载于:https://dev.to/drumbler9/working-with-sorted-lists-in-python-magic-of-the-bisect-module-2c3m?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何在 Go 通道中有效地生成不同的值?
    如何在 Go 通道中有效地生成不同的值?
    在 Go Channel 中高效生成不同值在 Go 中,Channel 为并发通信提供了强大的机制。但是,在使用通道时,您可能会遇到需要过滤掉重复值或确保仅发出不同值的情况。本文探讨了创建仅输出唯一值的通道的有效方法。生成不同值的挑战考虑以下场景:您有一个通道接收多个值,并且您希望迭代它,同时仅打印...
    编程 发布于2024-11-06
  • 如何使用 Tailwind CSS 设置 os Next.js
    如何使用 Tailwind CSS 设置 os Next.js
    要使用 Tailwind CSS 设置 Next.js,请按照以下步骤操作: 第 1 步:创建一个新的 Next.js 项目 如果您尚未创建 Next.js 项目,您可以使用 create-next-app 创建一个项目。 npx create-next-app@latest my-...
    编程 发布于2024-11-06
  • 如何解决 PHPmailer HTML 内容渲染问题?
    如何解决 PHPmailer HTML 内容渲染问题?
    PHPmailer 无法渲染 HTML 内容使用 PHPmailer 发送电子邮件时,用户遇到 HTML 代码显示为原始文本的问题交货时。尽管使用了 IsHTML() 方法,所需的 HTML 内容仍然无法访问。潜在问题此行为背后的原因在于方法调用的顺序。与它的前身不同,PHPMailer 6 要求在...
    编程 发布于2024-11-06
  • 如何使用 Java 从 HTML 文档中提取数据?
    如何使用 Java 从 HTML 文档中提取数据?
    Java HTML解析要从网站获取数据,首先必须了解HTML文档的结构。 HTML 元素使用标签进行组织,标签指定每个元素的类型和内容。例如,以下 HTML 表示具有特定 CSS 类的 div 标签:<div class="classname"></div>...
    编程 发布于2024-11-06
  • 为什么 Java 异常处理代码会产生“132Exception in thread main MyExc1”而不是“13Exception in thread main MyExc2”?
    为什么 Java 异常处理代码会产生“132Exception in thread main MyExc1”而不是“13Exception in thread main MyExc2”?
    Java中的异常处理:解开歧义在一个令人费解的Java异常处理场景中,一个大学问题提出了以下代码片段: // Exception Heirarchy class MyExc1 extends Exception {} class MyExc2 extends Exception {} class M...
    编程 发布于2024-11-06
  • 从 shell 脚本迁移到“Bun 脚本”
    从 shell 脚本迁移到“Bun 脚本”
    在 zCloud 从事专注于流程自动化和基础设施的项目时,我们经常遇到需要创建多个函数来执行验证和通用流程的情况。仅使用一种操作系统时一切正常,但当涉及多个系统时情况会变得复杂。 在我们的例子中,大部分开发都发生在 Linux 上,但我们还需要确保与 macOS 的兼容性。这通常会导致代码不兼容。 ...
    编程 发布于2024-11-06
  • 您的 Web 项目中 jQuery 库的最佳来源在哪里?
    您的 Web 项目中 jQuery 库的最佳来源在哪里?
    您应该从哪里获取 jQuery 库?当您的项目中包含 jQuery 和 jQuery UI 时,有多个选项可用。让我们深入研究一下每种方法的优缺点。Google JSAPI 与 CDNGoogle JSAPI 提供了一种从 Google 分布式服务器访问 jQuery 的便捷方法。这可以缩短加载时间...
    编程 发布于2024-11-06
  • PHP 设计模式:适配器
    PHP 设计模式:适配器
    适配器设计模式是一种结构模式,允许具有不兼容接口的对象一起工作。它充当两个对象之间的中介(或适配器),将一个对象的接口转换为另一个对象期望的接口。这允许那些因为具有不同接口而不兼容的类在不修改其原始代码的情况下进行协作。 适配器结构 适配器模式一般由三个主要元素组成: 客户端:期望与特定接口的对象一...
    编程 发布于2024-11-06
  • 了解 PHP 中的 WebSocket
    了解 PHP 中的 WebSocket
    WebSockets 通过单个 TCP 连接提供实时、全双工通信通道。与 HTTP 不同,HTTP 中客户端向服务器发送请求并等待响应,WebSocket 允许客户端和服务器之间进行连续通信,而无需多次请求。这非常适合需要实时更新的应用程序,例如聊天应用程序、实时通知和在线游戏。 在本指南中,我们将...
    编程 发布于2024-11-06
  • Visual Studio 2012 支持哪些 C++11 功能?
    Visual Studio 2012 支持哪些 C++11 功能?
    Visual Studio 2012 中的 C 11 功能随着最近发布的 Visual Studio 2012 预览版,许多开发人员对 C 11 功能的支持感到好奇。虽然 Visual Studio 2010 已提供部分 C 11 支持,但新版本提供了扩展的功能。Visual Studio 2012...
    编程 发布于2024-11-06
  • 如何在Windows启动时自动运行Python脚本?
    如何在Windows启动时自动运行Python脚本?
    在 Windows 启动时运行 Python 脚本每次 Windows 启动时执行 Python 脚本对于自动化任务或启动基本程序至关重要。多种方法提供不同级别的自定义和用户控制。自动执行脚本的选项:1。打包为服务:创建 Windows 服务并安装它。此方法在计算机上运行脚本,无论用户是否登录。需要...
    编程 发布于2024-11-06
  • 探索 Astral.CSS:彻底改变网页设计的 CSS 框架。
    探索 Astral.CSS:彻底改变网页设计的 CSS 框架。
    在快节奏的 Web 开发世界中,框架在帮助开发人员高效创建具有视觉吸引力和功能性的网站方面发挥着关键作用。在当今可用的各种框架中,Astral CSS 因其独特的设计理念和易用性而脱颖而出。本文深入探讨了 Astral CSS 的功能、优点和总体影响。 什么是星界? Astral 是一个现代 CSS...
    编程 发布于2024-11-06
  • ESnd 箭头函数综合指南
    ESnd 箭头函数综合指南
    ES6简介 ECMAScript 2015,也称为 ES6 (ECMAScript 6),是对 JavaScript 的重大更新,引入了新的语法和功能,使编码更高效、更易于管理。 JavaScript 是用于 Web 开发的最流行的编程语言之一,ES6 的改进大大增强了其功能。 本...
    编程 发布于2024-11-06
  • 揭示算法和数据结构:高效编程的基础
    揭示算法和数据结构:高效编程的基础
    在这一系列文章中,我将分享我的学习历程,涉及在学术环境和大型科技公司中广泛讨论的两个主题:算法和数据结构。尽管这些主题乍一看似乎令人畏惧,特别是对于像我这样由于其他职业挑战而在整个职业生涯中没有机会深入研究这些主题的人,但我的目标是让它们易于理解。 我将从最基本的概念开始,然后转向更高级的主题,创建...
    编程 发布于2024-11-06
  • 如何使用 pprof 来分析 Go 程序中的 goroutine 数量?
    如何使用 pprof 来分析 Go 程序中的 goroutine 数量?
    使用 pprof 分析 Goroutine 数量检测 Go 程序中潜在的 Goroutine 泄漏需要监控一段时间内活动的 Goroutine 数量。虽然标准 go 工具 pprof 命令提供了对阻塞的深入了解,但它并不直接解决 goroutine 计数问题。要有效地分析 goroutine 数量,...
    编程 发布于2024-11-06

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3