1. 程式人生 > 其它 >Python-二分查詢演算法bisect模組

Python-二分查詢演算法bisect模組

技術標籤:pythonpython資料結構二分查詢

目錄

簡介

方法

二分查詢

目標值區間左側

目標值區間右側

插入【可不學】

目標值區間左側

目標值區間左側

參考


簡介

方法

二分查詢

目標值區間左側

bisect_left(a, x, lo=0, hi=len(a))

a 中找到 x 合適的插入點以維持有序。引數 lohi 可以被用於確定需要考慮的子集;預設情況下整個列表都會被使用。如果 x 已經在 a 裡存在,那麼插入點會在已存在元素之前(也就是左邊)。如果 a 是列表(list)的話,返回值是可以被放在 list.insert(index,object) 的第一個引數的。

返回的插入點 i 可以將陣列 a 分成兩部分。左側是 all(val < x for val in a[lo:i]) ,右側是 all(val >= x for val in a[i:hi])

>>> from bisect import *
>>> lst = [1,2,2,5]
>>> bisect_left(lst,4)
3
>>> lst[:3]
[1, 2, 2]
>>> lst[3:]
[5]

對於列表lst來說,以bisect_left返回的index為界限,lst[:index]為小於x的,lst[index:]為大於或等於x的。

>>> lst.insert(bisect_left(lst,4),4)
>>> lst[3]
4

使用insert方法插入x後,x就是在bisect_left返回的那個索引位置

原始碼

def bisect_left(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e < x, and all e in
    a[i:] have e >= x.  So if x already appears in the list, a.insert(x) will
    insert just before the leftmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if a[mid] < x: lo = mid+1
        else: hi = mid
    return lo

注意,原始碼使用的是(lo+hi)//2,如果使用模組刷題時超時(Python自動轉為大數運算,時間過長),可自己寫個二分查詢,改為lo+(hi-lo)//2。

目標值區間右側

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

bisect.bisect(a, x, lo=0, hi=len(a))

類似於bisect_left(a, x, lo=0, hi=len(a)),但是返回的插入點是 a 中已存在元素 x 的右側。

返回的插入點 i 可以將陣列 a 分成兩部分。左側是 all(val <= x for val in a[lo:i]),右側是 all(val > x for val in a[i:hi])

>>> bisect_right(lst,4)
4
>>> lst[:4]
[1, 2, 2, 4]
>>> lst[4:]
[5]

對於列表lst來說,以bisect_left返回的index為界限,lst[:index]為小於或等於x的,lst[index:]為大於x的。

>>> lst.insert(bisect_right(lst,4),4)
>>> lst[4]
4

注意,已存在的4是lst[3],新插入的4是lst[4]

插入【可不學】

目標值區間左側

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

x 插入到一個有序序列 a 裡,並維持其有序。如果 a 有序的話,這相當於 a.insert(bisect.bisect_left(a, x, lo, hi), x)。要注意搜尋是 O(log n) 的,插入卻是 O(n) 的。

注意,是insort_left,不是insert_left,意思是insert到一個sort後的序列。

>>> insort_left(lst,3)
>>> lst
[1, 2, 2, 3, 4, 4, 5]

原始碼

def insort_left(a, x, lo=0, hi=None):
    """Insert item x in list a, and keep it sorted assuming a is sorted.

    If x is already in a, insert it to the left of the leftmost x.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if a[mid] < x: lo = mid+1
        else: hi = mid
    a.insert(lo, x)

目標值區間左側

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

bisect.insort(a, x, lo=0, hi=len(a))

類似於insort_left(a, x, lo=0, hi=len(a)),但是把 x 插入到 a 中已存在元素 x 的右側。

>>> insort_right(lst,3)
>>> lst
[1, 2, 2, 3, 3, 4, 4, 5]

注:看原始碼發現真的沒有效能提升,裡面就是呼叫的insert,可以不學插入這兩個函式。

參考

python-陣列二分查詢演算法

更多python相關內容:【python總結】python學習框架梳理

本人b站賬號:lady_killer9

有問題請下方評論,轉載請註明出處,並附有原文連結,謝謝!如有侵權,請及時聯絡。如果您感覺有所收穫,自願打賞,可選擇支付寶18833895206(小於),您的支援是我不斷更新的動力。