用bisect来管理已排序的序列

bisect模块包含两个函数,bisect和insert,两个函数都利用二分查找算法在有序序列中查找或插入元素

 

用bisect来搜索

bisect(ordered_sequence, needle)

ordered_sequence:必须是一个有序的序列

needle:指定序列中需要搜索的位置数

ordered_sequence和needle只是举栗子的位置参数,无需关注

栗子:


gg = [33, 99, 77, 70, 89, 90, 100]
print(bisect.bisect(gg, 100))

运行后的结果如下

7

从运行的结果可以看出,查找的是元素插入的索引位置并返回出来,这点要注意...

bisect函数其实是bisect_right函数的别名,就是进行了赋值操作,图片如下:

用bisect来管理已排序的序列_第1张图片

再看下bisect_right函数的源码:


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)

首先是两个位置参数 :

  • a 就是我们要传 的有序的序列

  • b 就是我们要查询的元素值

其次是两个关键字参数,主要是用来缩小搜寻的范围:

  • lo 的默认值是0

  • hi 的默认值是None,但是又加了if判断,如果为None,默认值就变成了有序序列的长度,也就是len(a)

源码中的while处,是利用了二分查找算法在有序序列中查找元素,针对算法这块的可自行百度...

 

bisect_right函数还有一个姊妹函数叫bisect_left,区别如下

 

  • bisect_right:

若序列a中存在与x相同的元素,则返回x相等元素右侧插入点的索引位置

若序列a中不存在与x相同的元素,则返回与x左侧距离最近元素插入点的索引位置

 

栗子:


gg = [33, 70, 77, 89, 90, 99, 100]
print(bisect.bisect_right(gg, 100))
print(bisect.bisect_right(gg, 101))

运行后的结果如下

7
7

100存在列表中,返回右边插入点的索引位置是7;101在列表中不存在,取距离最近的插入点索引位置是也是7

 

  • bisect_left:

若序列a中存在与x相同的元素,则返回x相等元素左侧插入点的索引位置

若序列a中不存在与x相同的元素,则返回与x右侧距离最近元素插入点的索引位置

 

栗子:


gg = [33, 70, 77, 89, 90, 99, 100]
print(bisect.bisect_left(gg, 100))
print(bisect.bisect_left(gg, 101))

运行后的结果如下

6
7

100存在列表中,返回左边插入点的索引位置是6;101在列表中不存在,返回距离最近的插入点索引位置是7

 

使用bisect()函数来进行数字表查询,从一个给定的考试成绩集合里,通过一个有序的数字表,查出其对应的字符等级:90分及以上的是’A‘,80到89是’B‘,以此类推...

栗子:

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

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

运行后的结果如下

['F', 'A', 'C', 'C', 'B', 'A', 'A']
  • score为33时,插入点索引位置为0,取值是F

  • score为99时,插入点索引位置为4,取值是A

  • score为77时,插入点索引位置为2,取值是C

  • score为70时,插入点索引位置为2,取值是C

  • score为89时,插入点索引位置为3,取值是B

  • score为90时,插入点索引位置为4,取值是A

  • score为100时,插入点索引位置为4,取值是A

 

用insort来插入

insort(ordered_sequence, needle)

ordered_sequence:必须是一个有序的序列

needle:指定序列中需要搜索的位置数

ordered_sequence和needle只是举栗子的位置参数,无需关注

 

栗子:


gg = [33, 70, 77, 89, 90, 99, 100]

bisect.insort(gg, 50)
print(gg)

运行后的结果如下

[33, 50, 70, 77, 89, 90, 99, 100]

从上述结果显示可以看出,数据插入时不会破坏有序的列表,相反插入的数据还是自动排序好的

 

insort函数其实是insort_right函数的别名,就是进行了赋值操作,图片如下:

用bisect来管理已排序的序列_第2张图片

 

insort_right函数还有一个姊妹函数叫insort_left,区别如下

 

  • insort_right:

若序列a中存在与x相同的元素,则返回x相等元素右侧插入点的索引位置并执行真正的插入

若序列a中不存在与x相同的元素,则返回与x左侧距离最近元素插入点的索引位置并执行真正的插入

首先插入序列中不存在的数据

栗子:

gg = [33, 70, 77, 89, 90, 99, 100]


print(bisect.bisect_right(gg, 50))
bisect.insort_right(gg, 50)
print(gg)

运行后的结果如下

1
[33, 50, 70, 77, 89, 90, 99, 100]

上述代码中使用bisect_right函数查到插入点索引位置为1,运行后插入到70前面,也就是索引1的位置

 

其次插入序列中存在的数据

栗子:

gg = [33, 70, 77, 89, 90, 99, 100]


print(bisect.bisect_right(gg, 70))
bisect.insort_right(gg, 70)
print(gg)

运行后的结果如下

2
[33, 70, 70, 77, 89, 90, 99, 100]

上述代码中使用bisect_right函数查询出插入点索引位置为2,运行后插入到70后面,也就是索引2的位置

 

最后就是insort_left函数

 

  • insort_left:

若序列a中存在与x相同的元素,则返回x相等元素左侧插入点的索引位置并执行真正的插入

若序列a中不存在与x相同的元素,则返回与x右侧距离最近元素插入点的索引位置并执行真正的插入

 

insort_left的插入可自行操作以便增加理解,可能刚开始对bisect查询返回的插入索引位置有些迷惑,多操作几遍就慢慢理解了...

 

 

以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,评论区留言会及时修正发布,谢谢!

微信搜索公众号:就用python

用bisect来管理已排序的序列_第3张图片

 

 

你可能感兴趣的:(python,python,baisect)