[算法]:二分法-查找有序數組中一個數字位置


#問題
二分查找

list.index()無法應對大規模數據的查詢,需要用其它方法解決,這里談的就是二分查找

#思路說明

在查找方面,python中有list.index()的方法。例如:

>>> a=[2,4,1,9,3] #list可以是無序,也可以是有序
>>> a.index(4) #找到后返回該值在list中的位置
1
>>> a.index(5) #如果沒有該值,則報錯
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 5 is not in list

這是python中基本的查找方法,雖然簡單,但是,如果由於其時間復雜度為O(n),對於大規模的查詢恐怕是不足以勝任的。二分查找就是一種替代方法。

二分查找的對象是:有序數組。這點特別需要注意。要把數組排好序先。怎么排序,可以參看我這里多篇排序問題的文章。

基本步驟:

1. 從數組的中間元素開始,如果中間元素正好是要查找的元素,則搜素過程結束;
2. 如果某一特定元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。
3. 如果在某一步驟數組為空,則代表找不到。

這種搜索算法每一次比較都使搜索范圍縮小一半。時間復雜度:O(logn)
# 遞歸
def binary_search(lst, value, lo, hi):
    if lo > hi:
        return -1
    half = (lo + hi)/2
    if lst[half] == value:
        return half
    elif lst[half] > value:
        return binary_search(lst, value, lo, half-1)
    else:
        return binary_search(lst, value, half+1, hi)


# 循環
def binary_search_while(lst, value):
    lo, hi = 0, len(lst)-1
    while lo <= hi:
        half = (lo + hi)/2
        if lst[half] > value:
            hi = half - 1
        elif lst[half] < value:
            lo = half + 1
        else:
            return half
    return -1
 
         
         
        

 

 
        
對於python,不能忽視其強大的標准庫。經查閱,發現標准庫中就有一個模塊,名為:bisect。


- 模塊接受排序后的列表。
- 本模塊同樣適用於長列表項。因為它就是用二分查找方法實現的,有興趣可以看其源碼(源碼是一個很好的二分查找算法的例子,特別是很好地解決了邊界條件極端的問題.)
- 關於bisect模塊的更多內容,可以參看[官方文檔](https://docs.python.org/2/library/bisect.html)
 
        
"""Bisection algorithms."""

def insort_right(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 right of the rightmost 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 x < a[mid]: hi = mid
        else: lo = mid+1
    a.insert(lo, x)

insort = insort_right   # backward compatibility

def bisect_right(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 after the rightmost 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 x < a[mid]: hi = mid
        else: lo = mid+1
    return lo

bisect = bisect_right   # backward compatibility

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)


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

# Overwrite above definitions with a fast C implementation
try:
    from _bisect import *
except ImportError:
    pass
 
        

 參考資料:https://github.com/qiwsir/algorithm

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM