[source code co reading] detailed explanation of bisect module of built-in bisection algorithm (half algorithm) in Python

Keywords: Python Algorithm

1. Introduction

Bisection algorithm is a very common and commonly used algorithm in programming. Even so, I didn't expect that Python official has a special module to realize most operations of the algorithm. The module is bisect.

In fact, the functions provided by this module are mainly used in such a scenario, that is, after each use of the functions to insert an element into the list, the list can be kept in order without sorting. This can improve the efficiency of code in the scenario where there are many list elements and the comparison between elements is very time-consuming.

2. Source code

"""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.
    """

    lo = bisect_right(a, x, lo, hi)
    a.insert(lo, x)

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

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.
    """

    lo = bisect_left(a, x, lo, hi)
    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

# Create aliases
bisect = bisect_right
insort = insort_right

3. Analysis

In fact, the module is very simple, just for the dichotomy algorithm 4 4 Four functions implement the bisection algorithm 4 4 4 common operations:

3.1 bisect_left(a, x, lo=0, hi=None)

Assuming that a is an ordered sequence, this function returns an index i, which determines where element x should be inserted to ensure that a is still an ordered sequence.

The return value i of this function satisfies the following properties:

  • For any element E in a[:i], e < x;
  • For any element e in a[i:], e > = X.

Therefore, if x already exists in a, a.insert(i, x) will insert x at the previous position of the leftmost X in the existing X in a.

The optional parameter lo (default is 0 0 0) and hi (the default is len(a)) are used to determine the boundary of binary search.

3.2 bisect_right(a, x, lo=0, hi=None)

Assuming that a is an ordered sequence, this function returns an index i, which determines where element x should be inserted to ensure that a is still an ordered sequence.

The return value i of this function satisfies the following properties:

  • For any element E in a[:i], e < = x;
  • For any element e in a[i:], e > X.

Therefore, if x already exists in a, a.insert(i, x) will insert x at the last position of the rightmost X in the existing X in a.

The optional parameter lo (default is 0 0 0) and hi (the default is len(a)) are used to determine the boundary of binary search.

3.3 insort_left(a, x, lo=0, hi=None)

This function inserts element x into a to ensure that a is orderly before insertion and a is orderly after insertion.

If x already exists in a, the element x will be inserted in the previous position of the leftmost X.

The optional parameter lo (default is 0 0 0) and hi (the default is len(a)) are used to determine the boundary of binary search.

3.4 insort_right(a, x, lo=0, hi=None)

This function inserts element x into a to ensure that a is orderly before insertion and a is orderly after insertion.

If x already exists in a, the element x will be inserted in the last position of the rightmost X.

The optional parameter lo (default is 0 0 0) and hi (the default is len(a)) are used to determine the boundary of binary search.

Posted by s0me0ne on Sun, 12 Sep 2021 13:30:13 -0700