vlambda博客
学习文章列表

最简单的方法实现 Python数组二分查找算法

bisect 数组二分查找算法

不想自己手写二分查找?

可以,一个 import bisect 帮你完成开包即用的 Binary Search

bisect 是一个python标准库,直接导入就可以使用。

方法1: bisect.bisect_left()

bisect.bisect_left(a, x, lo=0, hi=len(a))
参数说明:
  • a:表示插入的数组
  • x:即将插入到数组中的一个数值类型的元素
返回值:元素x插入到数组a后在数组中的位置索引(不执行插入操作,只计算索引,数组a保持不变),如果x在a中已经存在,则x插入到已存在元素的左侧。
例子:

可以看到,元素8在插入到数组a后的位置索引为 3,新插入的元素x(8)在已经存在数组a中的元素8的左侧。

方法2: bisect.bisect_right()

bisect.bisect_right(a, x, lo=0, hi=len(a))
参数说明:
  • a:表示插入的数组
  • x:即将插入到数组中的一个数值类型的元素
返回值:元素x插入到数组a后在数组中的位置索引(不执行插入操作,只计算索引,数组a保持不变),如果x在a中已经存在,则x插入到已存在元素的右侧。
例子:

最简单的方法实现 Python数组二分查找算法

可以看到,元素8在插入到数组a后的位置索引为 4,新插入的元素x(8)在已经存在数组a中的元素8的右侧。

方法3: bisect.bisect()

bisect.bisect(a, x, lo=0, hi=len(a))

效果同 bisect_right,可以看作是 bisect_right 的缩写。

方法4: bisect.insort_left()

bisect.insort_left(a, x, lo=0, hi=len(a))

同 bisect_left 原理一致,只不过 bisect_left 不真正执行插入操作,而 insort_left 执行插入操作,数组a发生改变。

相当于

a.insert(bisect.bisect_left(a, x, lo, hi), x)
例子:

最简单的方法实现 Python数组二分查找算法

这里红圈的 8 就是插入的参数 x

方法5: bisect.insort_right()

bisect.insort_right(a, x, lo=0, hi=len(a))

同 bisect_right 原理一致,只不过 bisect_right 不真正执行插入操作,而 insort_right 执行插入操作,数组a发生改变。

相当于

a.insert(bisect.bisect_right(a, x, lo, hi), x)
例子:

最简单的方法实现 Python数组二分查找算法

这里红圈的 8 就是插入的参数 x,注意和 insort_left 的区别。

方法6: bisect.insort()

bisect.insort(a, x, lo=0, hi=len(a))

效果同 insort_right,可以看作是 insort_right 的缩写。

应用

查询 x 是否在数组 a 中, 如果在返回位置索引

a=[1, 5, 7, 8, 9]

def index(a, x):
    i = bisect.bisect_left(a, x)
    if i != len(a) and a[i] == x:
        return i
    raise ValueError

注意:如果有重复值,返回最左侧位置的索引

类似数据分组

函数 bisect() 还可以用于数字表查询。这个例子是使用 bisect() 从一个给定的考试成绩集合里,通过一个有序数字表,查出其对应的字母等级:90 分及以上是 'A',80 到 89 是 'B',以此类推。

def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
    i = bisect.bisect(breakpoints, score)
    return grades[i]

[grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]