Python Glossary Русский

all Python 3Algorithms & data structuresterm

Binary search

search

A search in a sorted array in O(log n). Every step halves the range being searched.

Syntax

def binary_search(arr, target):

The core trap is that the data must already be sorted: on an unsorted list the search does not raise anything, it just quietly returns a wrong answer. Sorting for the sake of one lookup does not pay off — O(n log n) costs more than a plain in check at O(n); the win appears when the same array is searched many times. You rarely need to hand-roll it: bisect_left gives the insertion point and you only compare the item sitting there with the target, and the (lo + hi) overflow that broke this algorithm for years in C and Java cannot happen in Python.

Examples

def binary_search(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1
print(binary_search([1,3,5,7,9,11], 7))  # → 3
print(binary_search([1,3,5,7,9,11], 6))  # → -1
# bisect — стандартная библиотека
import bisect
arr = [1,3,5,7,9]
print(bisect.bisect_left(arr, 5))  # → 2 (позиция для вставки)
print(bisect.bisect_right(arr, 5))  # → 3
# Рекурсивный вариант
def bs_rec(arr, target, lo=0, hi=None):
    if hi is None: hi = len(arr)-1
    if lo > hi: return -1
    mid = (lo+hi)//2
    if arr[mid] == target: return mid
    elif arr[mid] < target: return bs_rec(arr, target, mid+1, hi)
    else: return bs_rec(arr, target, lo, mid-1)
print(bs_rec([2,4,6,8,10], 6))  # → 2
# Поиск первого вхождения дубликата
def first_occurrence(arr, target):
    lo, hi, result = 0, len(arr)-1, -1
    while lo <= hi:
        mid = (lo+hi)//2
        if arr[mid] == target:
            result = mid; hi = mid-1
        elif arr[mid] < target: lo = mid+1
        else: hi = mid-1
    return result
print(first_occurrence([1,2,2,2,3], 2))  # → 1
# Бинарный поиск ответа
def min_pages(pages, students):
    lo, hi = max(pages), sum(pages)
    def can_split(limit):
        count, cur = 1, 0
        for p in pages:
            if cur + p > limit: count+=1; cur=0
            cur += p
        return count <= students
    while lo < hi:
        mid = (lo+hi)//2
        if can_split(mid): hi=mid
        else: lo=mid+1
    return lo
print(min_pages([10,20,30,40], 2))  # → 60
# bisect.insort — вставка в отсортированный список
import bisect
arr2 = [1,3,5,9]
bisect.insort(arr2, 6)
print(arr2)  # → [1,3,5,6,9]

See also

Open in the full glossarydocs.python.orgReport an inaccuracy