Python笔记:bisect库简介

1. bisect库是什么

今天在做题的时候偶然发现python中有一个强大的内置库,即bisect库,它能够轻易地实现顺序列表中的二分查找与插入操作

因此,这里,我们就来简单地看一下bisect库使用方法。

它非常地简单,仅包含以下6个函数:

  1. bisect_left(nums, tgt, lo=0, hi=len(nums))
  2. bisect_right(nums, tgt, lo=0, hi=len(nums))
  3. bisect(nums, tgt, lo=0, hi=len(nums))
  4. insort_left(nums, tgt, lo=0, hi=len(nums))
  5. insort_right(nums, tgt, lo=0, hi=len(nums))
  6. insort(nums, tgt, lo=0, hi=len(nums))

其中,2和3以及5和6本质上来说又是完全相同的(后面我们不会再对其进行区分),因此,事实上bisect库中仅仅包含有4个函数,其中bisect_left()bisect()用于二分查找,而insort_left()insort()用于数据的插入。

2. 二分查找操作

二分查找是bisect给出的最核心功能,顾名思义,就是提供了二分查找方法,使得可以在 O ( l o g ( N ) ) O(log(N)) O(log(N))时间复杂度的情况下准确地找到元素的目标位置。

1. bisect内置函数说明

我们使用bisect()函数或者bisect_left()函数即可快速地实现顺序列表中任意一个元素的查找。

但是,需要强调的是,bisect提供的查找操作并非是直接找到目标元素的位置,而是找到如果要插入元素,则应当插入的位置

例如:

from bisect import *

nums = [1,2,3]
bisect_left(nums, 0) # 0
bisect_left(nums, 1) # 0
bisect_right(nums, 1) # 1

nums = [1,1,1,1]
bisect_left(nums, 1) # 0
bisect_right(nums, 1) # 4

用python语言来翻译一下这两个函数的话,应该为:

def bisect_left(nums, tgt, lo=0, hi=len(nums)):
    if lo >= hi or nums[lo] >= tgt:
        return lo
    if nums[hi-1] < tgt:
        return hi
    while hi-lo > 1:
        mid = (hi+lo) // 2
        if nums[mid] >= tgt:
            hi = mid
        else:
            lo = mid
    return lo

def bisect_right(nums, tgt, lo=0, hi=len(nums)):
    if lo >= hi or nums[lo] > tgt:
        return lo
    if nums[hi-1] <= tgt:
        return hi
    while hi-lo > 1:
        mid = (hi+lo) // 2
        if nums[mid] > tgt:
            hi = mid
        else:
            lo = mid
    return hi

2. 单纯的二分查找实现方法

由上,如果单纯就是要使用bisect来实现一个二分查找,如果找到则返回idx,否则返回-1的话,正确的实现应该为:

from bisect import *

def bi_search(nums, tgt):
    idx = bisect_left(nums, tgt)
    if idx == len(nums) or nums[idx] != tgt:
        return -1
    return idx

nums = [1,2,3]
bi_search(nums, 1) # 0
bi_search(nums, 5) # -1

3. 插入 & 删除操作

基于上述二分查找的结果,我们可以快速地完成有序数列的插入以及删除操作。

不过,如前所述,插入操作事实上bisect库本身已经提供了对应的插入函数。

删除操作虽然没有提供相应的操作,但是我们同样可以快速地进行自定义实现。

1. 数据的插入

bisect库中自带了insort_left()以及insort_right()两个插入函数,他们的实现也非常的trival,分别定义如下:

def insort_left(nums, tgt, lo=0, hi=len(nums)):
    idx = bisect_left(nums, tgt, lo, hi)
    nums.insert(idx, tgt)
    return

def insort_right(nums, tgt, lo=0, hi=len(nums)):
    idx = bisect_right(nums, tgt, lo, hi)
    nums.insert(idx, tgt)
    return

因此,我们只需要使用上述两个内置函数,就能轻易地实现顺序列表中数据的顺序插入。

但是,需要注意的是,虽然insort方法在index的检索上的时间复杂度仅为 O ( l o g ( N ) ) O(log(N)) O(log(N)),但是插入操作insert的时间复杂度却是 O ( N ) O(N) O(N)的,因此,整体的插入操作的时间复杂度依然还是 O ( N ) O(N) O(N)量级的

2. 数据的删除

同样地,仿照上述我们自定义实现的数据查找方法,我们同样可以快速给出基于bisect库的数据删除操作。

from bisect import *

def bi_delete(nums, tgt):
    idx = bisect_left(nums, tgt)
    if idx < len(nums) and nums[idx] == tgt:
        nums.pop(idx)
    return 

nums = [1,1,1]
bi_delete(nums, 1) # nums = [1,1]

同样,受限于pop操作的时间复杂度,这一操作的整体时间复杂度还是在 O ( N ) O(N) O(N)量级。

4. 参考链接

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值