亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Python 二分查找與 bisect 模塊

URLOS / 2469人閱讀

摘要:對(duì)于大數(shù)據(jù)量,則可以用二分查找進(jìn)行優(yōu)化。有一個(gè)模塊,用于維護(hù)有序列表。和用于指定列表的區(qū)間,默認(rèn)是使用整個(gè)列表。模塊提供的函數(shù)可以分兩類只用于查找,不進(jìn)行實(shí)際的插入而則用于實(shí)際插入。

Python 的列表(list)內(nèi)部實(shí)現(xiàn)是一個(gè)數(shù)組,也就是一個(gè)線性表。在列表中查找元素可以使用 list.index() 方法,其時(shí)間復(fù)雜度為O(n)。對(duì)于大數(shù)據(jù)量,則可以用二分查找進(jìn)行優(yōu)化。二分查找要求對(duì)象必須有序,其基本原理如下:

1.從數(shù)組的中間元素開始,如果中間元素正好是要查找的元素,則搜素過程結(jié)束;

2.如果某一特定元素大于或者小于中間元素,則在數(shù)組大于或小于中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。

3.如果在某一步驟數(shù)組為空,則代表找不到。

二分查找也成為折半查找,算法每一次比較都使搜索范圍縮小一半, 其時(shí)間復(fù)雜度為 O(logn)。

我們分別用遞歸和循環(huán)來實(shí)現(xiàn)二分查找:

def binary_search_recursion(lst, value, low, high):
    if high < low:
        return None
    mid = (low + high) / 2
    if lst[mid] > value:
        return binary_search_recursion(lst, value, low, mid-1)
    elif lst[mid] < value:
        return binary_search_recursion(lst, value, mid+1, high)
    else:
        return mid

def binary_search_loop(lst,value):
    low, high = 0, len(lst)-1
    while low <= high:
        mid = (low + high) / 2
        if lst[mid] < value:
            low = mid + 1
        elif lst[mid] > value:
            high = mid - 1
        else:
            return mid
    return None

接著對(duì)這兩種實(shí)現(xiàn)進(jìn)行一下性能測(cè)試:

if __name__ == "__main__":
    import random
    lst = [random.randint(0, 10000) for _ in xrange(100000)]
    lst.sort()

    def test_recursion():
        binary_search_recursion(lst, 999, 0, len(lst)-1)

    def test_loop():
        binary_search_loop(lst, 999)

    import timeit
    t1 = timeit.Timer("test_recursion()", setup="from __main__ import test_recursion")
    t2 = timeit.Timer("test_loop()", setup="from __main__ import test_loop")

    print "Recursion:", t1.timeit()
    print "Loop:", t2.timeit()

執(zhí)行結(jié)果如下:

Recursion: 3.12596702576
Loop: 2.08254289627

可以看出循環(huán)方式比遞歸效率高。

Python 有一個(gè) bisect 模塊,用于維護(hù)有序列表。bisect 模塊實(shí)現(xiàn)了一個(gè)算法用于插入元素到有序列表。在一些情況下,這比反復(fù)排序列表或構(gòu)造一個(gè)大的列表再排序的效率更高。Bisect 是二分法的意思,這里使用二分法來排序,它會(huì)將一個(gè)元素插入到一個(gè)有序列表的合適位置,這使得不需要每次調(diào)用 sort 的方式維護(hù)有序列表。

下面是一個(gè)簡(jiǎn)單的使用示例:

import bisect
import random

random.seed(1)

print"New  Pos Contents"
print"---  --- --------"

l = []
for i in range(1, 15):
    r = random.randint(1, 100)
    position = bisect.bisect(l, r)
    bisect.insort(l, r)
    print"%3d  %3d" % (r, position), l

輸出結(jié)果:

New  Pos Contents
---  --- --------
 14    0 [14]
 85    1 [14, 85]
 77    1 [14, 77, 85]
 26    1 [14, 26, 77, 85]
 50    2 [14, 26, 50, 77, 85]
 45    2 [14, 26, 45, 50, 77, 85]
 66    4 [14, 26, 45, 50, 66, 77, 85]
 79    6 [14, 26, 45, 50, 66, 77, 79, 85]
 10    0 [10, 14, 26, 45, 50, 66, 77, 79, 85]
  3    0 [3, 10, 14, 26, 45, 50, 66, 77, 79, 85]
 84    9 [3, 10, 14, 26, 45, 50, 66, 77, 79, 84, 85]
 44    4 [3, 10, 14, 26, 44, 45, 50, 66, 77, 79, 84, 85]
 77    9 [3, 10, 14, 26, 44, 45, 50, 66, 77, 77, 79, 84, 85]
  1    0 [1, 3, 10, 14, 26, 44, 45, 50, 66, 77, 77, 79, 84, 85]

Bisect模塊提供的函數(shù)有:

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

查找在有序列表 a 中插入 x 的index。lo 和 hi 用于指定列表的區(qū)間,默認(rèn)是使用整個(gè)列表。如果 x 已經(jīng)存在,在其左邊插入。返回值為 index。

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

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

這2個(gè)函數(shù)和 bisect_left 類似,但如果 x 已經(jīng)存在,在其右邊插入。

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

在有序列表 a 中插入 x。和 a.insert(bisect.bisect_left(a,x, lo, hi), x) 的效果相同。

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

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

和 insort_left 類似,但如果 x 已經(jīng)存在,在其右邊插入。

Bisect 模塊提供的函數(shù)可以分兩類: bisect* 只用于查找 index, 不進(jìn)行實(shí)際的插入;而 insort* 則用于實(shí)際插入。該模塊比較典型的應(yīng)用是計(jì)算分?jǐn)?shù)等級(jí):

def grade(score,breakpoints=[60, 70, 80, 90], grades="FDCBA"):
    i = bisect.bisect(breakpoints, score)
    return grades[i]

print [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]

執(zhí)行結(jié)果:

["F", "A", "C", "C", "B", "A", "A"]

同樣,我們可以用 bisect 模塊實(shí)現(xiàn)二分查找:

def binary_search_bisect(lst, x):
    from bisect import bisect_left
    i = bisect_left(lst, x)
    if i != len(lst) and lst[i] == x:
        return i
    return None

我們?cè)賮頊y(cè)試一下它與遞歸和循環(huán)實(shí)現(xiàn)的二分查找的性能:

Recursion: 4.00940990448
Loop: 2.6583480835
Bisect: 1.74922895432

可以看到其比循環(huán)實(shí)現(xiàn)略快,比遞歸實(shí)現(xiàn)差不多要快一半。

Python 著名的數(shù)據(jù)處理庫 numpy 也有一個(gè)用于二分查找的函數(shù) numpy.searchsorted, 用法與 bisect 基本相同,只不過如果要右邊插入時(shí),需要設(shè)置參數(shù) side="right",例如:

>>> import numpy as np
>>> from bisect import bisect_left, bisect_right
>>> data = [2, 4, 7, 9]
>>> bisect_left(data, 4)
1
>>> np.searchsorted(data, 4)
1
>>> bisect_right(data, 4)
2
>>> np.searchsorted(data, 4, side="right")
2

那么,我們?cè)賮肀容^一下性能:

In [20]: %timeit -n 100 bisect_left(data, 99999)
100 loops, best of 3: 670 ns per loop

In [21]: %timeit -n 100 np.searchsorted(data, 99999)
100 loops, best of 3: 56.9 ms per loop

In [22]: %timeit -n 100 bisect_left(data, 8888)
100 loops, best of 3: 961 ns per loop

In [23]: %timeit -n 100 np.searchsorted(data, 8888)
100 loops, best of 3: 57.6 ms per loop

In [24]: %timeit -n 100 bisect_left(data, 777777)
100 loops, best of 3: 670 ns per loop

In [25]: %timeit -n 100 np.searchsorted(data, 777777)
100 loops, best of 3: 58.4 ms per loop

可以發(fā)現(xiàn) numpy.searchsorted 效率是很低的,跟 bisect 根本不在一個(gè)數(shù)量級(jí)上。因此 searchsorted 不適合用于搜索普通的數(shù)組,但是它用來搜索 numpy.ndarray 是相當(dāng)快的:

In [30]: data_ndarray = np.arange(0, 1000000)

In [31]: %timeit np.searchsorted(data_ndarray, 99999)
The slowest run took 16.04 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 996 ns per loop

In [32]: %timeit np.searchsorted(data_ndarray, 8888)
The slowest run took 18.22 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 994 ns per loop

In [33]: %timeit np.searchsorted(data_ndarray, 777777)
The slowest run took 31.32 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 990 ns per loop

numpy.searchsorted 可以同時(shí)搜索多個(gè)值:

>>> np.searchsorted([1,2,3,4,5], 3)
2
>>> np.searchsorted([1,2,3,4,5], 3, side="right")
3
>>> np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3])
array([0, 5, 1, 2])

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/43089.html

相關(guān)文章

  • Monorepo——大型前端項(xiàng)目的代碼管理方式

    摘要:目前最常見的解決方案是和的特性。具體的使用方法移步官網(wǎng)而使用作為包管理器的同學(xué),可以在中以字段聲明,就會(huì)以的方式管理。這樣的話,無論你的包管理器是還是,都能發(fā)揮的優(yōu)勢(shì)要是包管理是,就會(huì)把依賴安裝交給處理。 最近我接手了一個(gè)項(xiàng)目,代碼量比較大、有點(diǎn)復(fù)雜。倉庫 clone 下來代碼有 50+ MB,npm install 安裝完體積飚到了近 2GB …… 熟悉了一下,這個(gè)項(xiàng)目比較復(fù)雜,采用...

    ziwenxie 評(píng)論0 收藏0
  • Python學(xué)習(xí)之路21-序列構(gòu)成的數(shù)組

    摘要:第行把具名元組以的形式返回。對(duì)序列使用和通常號(hào)兩側(cè)的序列由相同類型的數(shù)據(jù)所構(gòu)成當(dāng)然不同類型的也可以相加,返回一個(gè)新序列。從上面的結(jié)果可以看出,它雖拋出了異常,但仍完成了操作查看字節(jié)碼并不難,而且它對(duì)我們了解代碼背后的運(yùn)行機(jī)制很有幫助。 《流暢的Python》筆記。接下來的三篇都是關(guān)于Python的數(shù)據(jù)結(jié)構(gòu),本篇主要是Python中的各序列類型 1. 內(nèi)置序列類型概覽 Python標(biāo)準(zhǔn)庫...

    ralap 評(píng)論0 收藏0
  • 跟黃申老師學(xué)數(shù)學(xué)(python實(shí)現(xiàn))-01迭代法

    摘要:在排好序的單詞列表中查找某個(gè)單詞優(yōu)化和的初始化,從開始,這樣避免只有時(shí)的優(yōu)化減少了內(nèi)存溢出的風(fēng)險(xiǎn)優(yōu)化循環(huán)時(shí),。 直觀定義 迭代法(Iterative Method),簡(jiǎn)單來說,其實(shí)就是不斷地用舊的變量值,遞推計(jì)算新的變量值。循環(huán)。 具體應(yīng)用 求數(shù)值的精確/近似解 二分法(Bisection method) 牛頓迭代法(Newton’s method) 在一定范圍內(nèi)查找目標(biāo)值...

    Nino 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<