」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 在 Python 中使用排序列表:「bisect」模組的魔力

在 Python 中使用排序列表:「bisect」模組的魔力

發佈於2024-08-28
瀏覽:962

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]刪除
最新教學 更多>
  • 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 201...
    程式設計 發佈於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 是一個現代 C...
    程式設計 發佈於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 數量使用 pprof 分析 Goroutine 數量檢測 Go 程式中潛在的 Goroutine 洩漏需要監控一段時間內活動的 Goroutine 數量。雖然標準 go 工具 pprof 命令提供了對阻塞的深入了解,但它並不直接解決 goroutine 計...
    程式設計 發佈於2024-11-06
  • 如何將類別方法作為回調傳遞:了解機制和技術
    如何將類別方法作為回調傳遞:了解機制和技術
    如何將類別方法作為回調傳遞後台在某些場景下,您可能需要將類別方法作為回調傳遞給其他函數以提高效率具體任務的執行。本文將引導您完成實現此目的的各種機制。 使用可調用語法要將函數作為回調傳遞,您可以直接將其名稱作為字串提供。但是,此方法不適用於類別方法。 傳遞實例方法類別實例方法可以使用陣列作為回調傳遞...
    程式設計 發佈於2024-11-06
  • 網頁抓取 - 有趣!
    網頁抓取 - 有趣!
    一個很酷的術語: CRON = 依指定時間間隔自動安排任務的程式設計技術 網路什麼? 在研究專案等時,我們通常會從各個網站編寫資訊 - 無論是日記/Excel/文件等。 我們正在抓取網路並手動提取資料。 網路抓取正在自動化這個過程。 例子 當在網路上搜尋運動鞋時...
    程式設計 發佈於2024-11-06
  • 感言網格部分
    感言網格部分
    ?在學習 CSS 網格時剛剛完成了這個推薦網格部分的建立! ?網格非常適合建立結構化佈局。 ?現場示範:https://courageous-chebakia-b55f43.netlify.app/ ? GitHub:https://github.com/khanimran17/Testimoni...
    程式設計 發佈於2024-11-06
  • 為什麼 REGISTER_GLOBALS 被認為是 PHP 中的主要安全風險?
    為什麼 REGISTER_GLOBALS 被認為是 PHP 中的主要安全風險?
    REGISTER_GLOBALS 的危險REGISTER_GLOBALS 是一個 PHP 設定,它允許所有 GET 和 POST 變數在 PHP 腳本中用作全域變數。此功能可能看起來很方便,但由於潛在的安全漏洞和編碼實踐,強烈建議不要使用它。 為什麼 REGISTER_GLOBALS 不好? REG...
    程式設計 發佈於2024-11-06
  • Nodemailer 概述:在 Node.js 中輕鬆發送電子郵件
    Nodemailer 概述:在 Node.js 中輕鬆發送電子郵件
    Nodemailer 是用於發送電子郵件的 Node.js 模組。以下是快速概述: Transporter:定義電子郵件的傳送方式(透過 Gmail、自訂 SMTP 等)。 const transporter = nodemailer.createTransport({ ... }); 訊息物...
    程式設計 發佈於2024-11-06
  • JavaScript 中的輕鬆錯誤處理:安全賦值運算子如何簡化您的程式碼
    JavaScript 中的輕鬆錯誤處理:安全賦值運算子如何簡化您的程式碼
    JavaScript 中的錯誤處理可能很混亂。將大塊程式碼包裝在 try/catch 語句中是可行的,但隨著專案的成長,調試就變成了一場噩夢。幸運的是,有更好的方法。輸入 安全賦值運算子 (?=) - 一種更乾淨、更有效的錯誤處理方法,可將程式碼保持可讀性並簡化偵錯。 什麼是安全賦...
    程式設計 發佈於2024-11-06
  • Javascript 很難(有悲傷)
    Javascript 很難(有悲傷)
    这将是一个很长的阅读,但让我再说一遍。 JAVASCRIPT很难。上次我们见面时,我正在踏入 Javascript 的世界,一个眼睛明亮、充满希望的程序员踏入野生丛林,说“这能有多难?”。我错得有多离谱??事情变得更难了,我(勉强)活了下来,这是关于我的旅程的一个小混乱的故事。 变量:疯狂的开始 ...
    程式設計 發佈於2024-11-06

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3