1. 程式人生 > 程式設計 >Python中bisect的使用方法

Python中bisect的使用方法

Python中列表(list)的實現其實是一個數組,當要查詢某一個元素的時候時間複雜度是O(n),使用list.index()方法,但是隨著資料量的上升,list.index()的效能也逐步下降,所以我們需要使用bisect模組來進行二分查詢,前提我們的列表是一個有序的列表。

遞迴二分查詢和迴圈二分查詢

def binary_search_recursion(lst,val,start,end):
  if start > end:
    return None
  mid = (start + end) // 2
  if lst[mid] < val:
    return binary_search_recursion(lst,mid + 1,end)
  if lst[mid] > val:
    return binary_search_recursion(lst,mid - 1)
  return mid
 
 
def binary_search_loop(lst,val):
  start,end = 0,len(lst) - 1
  while start <= end:
    mid = (start + end) // 2
    if lst[mid] < val:
      start = mid + 1
    elif lst[mid] > val:
      end = mid - 1
    else:
      return mid
  return None

為了比對一下兩者的效能,我們使用timeit模組來測試兩個方法執行,timeit模組的timeit方法預設會對需要測試的函式執行1000000,然後返回執行的時間。

>>> import random
>>> from random import randint
>>> from random import choice
>>> random.seed(5)
>>> lst = [randint(1,100) for _ in range(500000)]
>>> lst.sort()
>>> val = choice(lst)
>>> val
6
>>> def test_recursion():
...   return binary_search_recursion(lst,len(lst) - 1)
...
>>> def test_loop():
...   return binary_search_loop(lst,val)
...
>>> import timeit
>>> t1 = timeit.timeit("test_recursion()",setup="from __main__ import test_recursion")
>>> t1
3.9838006450511045
>>> t2 = timeit.timeit("test_loop()",setup="from __main__ import test_loop")
>>> t2
2.749765167240339

可以看到,迴圈二分查詢比遞迴二分查詢效能要來的好些。現在,我們先用bisect的二分查詢測試一下效能

用bisect來搜尋

>>> import bisect
>>> def binary_search_bisect(lst,val):
...   i = bisect.bisect(lst,val)
...   if i != len(lst) and lst[i] == val:
...     return i
...   return None
...
>>> def test_bisect():
...   return binary_search_bisect(lst,val)
...
>>> t3 = timeit.timeit("test_bisect()",setup="from __main__ import test_bisect")
>>> t3
1.3453236258177412

對比之前,我們可以看到用bisect模組的二分查詢的效能比迴圈二分查詢快一倍。再來對比一下,如果用Python原生的list.index()的效能

>>> def test_index():
...   return lst.index(val)
...
>>> t4 = timeit.timeit("test_index()",setup="from __main__ import test_index")
>>> t4
518.1656223725007

可以看到,如果用Python原生的list.index()執行1000000,需要500秒,相比之前的二分查詢,效能簡直慢到恐怖

用bisect.insort插入新元素

排序很耗時,因此在得到一個有序序列之後,我們最好能夠保持它的有序。bisect.insort就是為這個而存在的

insort(seq,item)把變數item插入到序列seq中,並能保持seq的升序順序

import random
from random import randint
import bisect
 
lst = []
SIZE = 10
random.seed(5)
for _ in range(SIZE):
  item = randint(1,SIZE)
  bisect.insort(lst,item)
  print('%2d ->' % item,lst)

輸出:

10 -> [10]
5 -> [5,10]
6 -> [5,6,10]
9 -> [5,9,10]
1 -> [1,5,10]
8 -> [1,8,10]
4 -> [1,4,1,10]
3 -> [1,3,10]
2 -> [1,2,10]

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。