Skip to main content

bisect二分模块

python模块 bisect

2020-07-08

有了这个模块,在处理二分法的lower bound和upper bound就不用自己吭呲吭呲的写代码了。不过这代码也简单,应该做到能随手写出来才行。

主要用到的是bisect_left和bisect_right, bisect_left确定的idx会大于或等于x,而bisect_right确定的idx会大于x。 感觉bisect_left和bisect_right之间最多只相差个1,在x不存在时候还应该相等。

In [46]: aarr = [1, 3, 7, 9, 20]

In [47]: bisect.bisect_left(aarr, 7)
Out[47]: 2

In [48]: bisect.bisect_right(aarr, 7)
Out[48]: 3

## 当6不存在于aarr列表中时,返回结果是一样的

In [49]: bisect.bisect_left(arr, 6)
Out[49]: 2

In [50]: bisect.bisect_right(arr, 6)
Out[50]: 2

使用有困惑的时候,ipython查看下说明就行了

In [42]: bisect.bisect_left?
Docstring:
bisect_left(a, x[, lo[, hi]]) -> index

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, i points 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.
Type: builtin_function_or_method

In [43]: bisect.bisect_right?
Docstring:
bisect_right(a, x[, lo[, hi]]) -> index

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, i points just
beyond the rightmost x already there

Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
Type: builtin_function_or_method

另外源码里面的写法都是right = len(n),对应的是while left < rgit还有分隔的时候right = mid;但我更习惯的写法是right = len(n) - 1,对应的也应该是while left <= right,还有处理的时候right = mid - 1

  • bisect.py

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

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

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

# Create aliases
bisect = bisect_right
insort = insort_right