bisect 的意思是 “平分,二等分”
bisect 是 python 的内置库,有两个模块:
bisect.bisect 二分查找模块,包括 bisect.bisect(), bisect.bisect_left() 和 bisect.bisect_right() 三个函数,返回值为查找元素的下标
bisect.bisect 可以用于非逆序系列的二分查找,即递增列表和乱序列表都可以使用
bisect.insort 插入模块, 包括 bisect.insort(), bisect.insort_left() 和 bisect.insort_right() 三个函数,返回值插入新元素后的列表
bisect.insort 只能在递增列表中插入新元素,即不能用于乱序和逆向列表
总结一下就是, bisect 库用于有序序列的插入和非逆序系列的二分查找
本节参考博客 Python中的bisect库(二分查找库)用法
bisect.bisect 模块包括三个函数,返回值为查找元素的下标:
我们在数组中进行查找目标值 target 时,会出现三种情况:
下面分别进行分析
import bisect
array = [1, 2, 3, 4, 7, 9, 9, 9, 9, 10] # len(array)=10
a = bisect.bisect(array, 6) # a=4
b = bisect.bisect_left(array, 6) # b=4
c = bisect.bisect_right(array, 6) # c=4
print(a, b, c)
此时三个函数的输出值都是一样的,输出的值都是在合适的插入点索引,使得数组有序。
import bisect
array = [1, 2, 3, 4, 7, 9, 9, 9, 9, 10] # len(array)=10
a = bisect.bisect(array, 7) # a=5
b = bisect.bisect_left(array, 7) # b=4
c = bisect.bisect_right(array, 7) # c=5
print(a, b, c)
bisect_left() 函数的输出是 target 在 list 中的数组下标,其余两个函数的输出下标+1
bisect_left() 的输出是符合用户直觉感受的,另外两个函数不符
import bisect
array = [1, 2, 3, 4, 7, 9, 9, 9, 9, 10] # len(array)=10
a = bisect.bisect(array, 9) # a=9
b = bisect.bisect_left(array, 9) # b=5
c = bisect.bisect_right(array, 9) # c=9
print(a, b, c)
bisect_left() 函数的输出是 target 在 list 中最左面值的数组下标,其余两个函数的输出为最右面的数组下标 +1
bisect_left() 的输出是符合用户直觉感受的,另外两个函数不符
不管什么情况,就用 bisect.bisect_left()
再次总结一下 bisect.bisect_left() 的用法:
import bisect
array = [1, 2, 3, 4, 7, 9, 9, 9, 9, 10] # len(array)=10
a = bisect.bisect_left(array, 6) # a=4
b = bisect.bisect_left(array, 7) # b=4
c = bisect.bisect_left(array, 9) # c=5
print(a, b, c)
乱序列表的元素查找见 2.5 小节
bisect 可以在非递减和逆序列表中查找元素,但不能用于倒序列表。以 bisect.bisect_left() 为例:
(1)乱序列表可以使用
import bisect
# 乱序列表
array = [1, 4, 2, 3, 7, 9, 9, 10, 9, 1] # len(array)=10
a = bisect.bisect_left(array, 6) # a=4 target不在数组中
b = bisect.bisect_left(array, 7) # b=4 target在数组中且只有一个
c = bisect.bisect_left(array, 9) # c=5 target在数组中并且有多个
print(a, b, c)
可以看到,在乱序列表中,bisect_left() 依然返回了 target 第一次出现的下标位置
(2)逆序列表不可以使用
import bisect
# 逆序列表
array = [10, 9, 9, 9, 8, 7, 6, 5, 3, 2] # len(array)=10
a = bisect.bisect_left(array, 6) # a=0 target不在数组中
b = bisect.bisect_left(array, 7) # b=0 target在数组中且只有一个
c = bisect.bisect_left(array, 9) # c=10 target在数组中并且有多个
print(a, b, c)
可以看到,在逆序列表中查找元素时,bisect_left() 的返回值是错误的
bisect.insort 模块用于将新元素插入非递减列表,得到的新列表依然是非递减的。且在原始列表有序的情况下, insort(), insort() 和 insort_right() 三个函数的作用是相同的,见代码示例:
import bisect
array = [1, 2, 4, 5, 6]
bisect.insort(array, 2)
print(array) # [1, 2, 2, 4, 5, 6]
bisect.insort_left(array, 3)
print(array) # [1, 2, 2, 3, 4, 5, 6]
bisect.insort_right(array, 7)
print(array) # [1, 2, 2, 3, 4, 5, 6, 7]
insort 模块只能用于非递减的有序列表,不能用于倒序和乱序列表:
(1)逆序列表不可以使用
bisect.insort():
import bisect
array = [6, 5, 4, 2, 1]
bisect.insort(array, 0)
print(array) # [0, 6, 5, 4, 2, 1]
bisect.insort(array, 3)
print(array) # [0, 3, 6, 5, 4, 2, 1]
bisect.insort(array, 5)
print(array) # [0, 3, 6, 5, 4, 2, 1, 5]
bisect.insort_left():
import bisect
array = [6, 5, 4, 2, 1]
bisect.insort_left(array, 0)
print(array) # [0, 6, 5, 4, 2, 1]
bisect.insort_left(array, 3)
print(array) # [0, 3, 6, 5, 4, 2, 1]
bisect.insort_left(array, 5)
print(array) # [0, 3, 5, 6, 5, 4, 2, 1]
bisect.insort_right():
import bisect
array = [6, 5, 4, 2, 1]
bisect.insort_right(array, 0)
print(array) # [0, 6, 5, 4, 2, 1]
bisect.insort_right(array, 3)
print(array) # [0, 3, 6, 5, 4, 2, 1]
bisect.insort_right(array, 5)
print(array) # [0, 3, 6, 5, 4, 2, 1, 5]
(2)乱序列表不可以使用
给乱序列表中插入元素本来就是没有太大意义的,此处代码验证省略。