bisect_left,bisect_right,bisect的用法,区别以源码分析

2023-12-19 03:36

本文主要是介绍bisect_left,bisect_right,bisect的用法,区别以源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

bisect_left(*args, **kwargs)

向一个数组插入一个数字,返回应该插入的位置。
如果这个数字不存在于这个数组中,则返回第一个比这个数大的数的索引
如果这个数字存在,则返回数组中这个数的位置的最小值(即最左边那个索引)

案例1:这个数在数组中不存在

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]# 在已排序的列表中查找元素 6 的插入位置
index = bisect_left(arr, 5.5)print(f"Insert 6 at index {index} to maintain sorted order.")

执行结果:

Insert 6 at index 4 to maintain sorted order.

我们找到了第一个大于5.5的数字6的位置,输出4

案例2:这个数在数组中存在

我们修改一下代码,寻找6的位置

from bisect import bisect_left, bisect, bisect_rightarr = [1, 3, 3, 5, 6, 6, 7, 9, 11]# 在已排序的列表中查找元素 6 的插入位置
index = bisect_left(arr, 6)print(f"Insert 6 at index {index} to maintain sorted order.")

执行结果:

Insert 6 at index 4 to maintain sorted order.

我们发现还是4

bisect_right(*args, **kwargs)

向一个数组插入一个数字,返回应该插入的位置。
作用:返回第一个比这个数大的数的索引

案例1:这个数在数组中不存在

from bisect import bisect_left, bisect, bisect_rightarr = [1, 3, 3, 5, 6, 6, 7, 9, 11]# 在已排序的列表中查找元素 6 的插入位置index = bisect_right(arr, 6.5)print(f"Insert 6 at index {index} to maintain sorted order.")

执行结果:

Insert 6 at index 6 to maintain sorted order.

数字7的位置被输出

案例2:这个数在数组中存在

from bisect import bisect_left, bisect, bisect_rightarr = [1, 3, 3, 5, 6, 6, 7, 9, 11]# 在已排序的列表中查找元素 6 的插入位置index = bisect_right(arr, 6)print(f"Insert 6 at index {index} to maintain sorted order.")

执行结果:

Insert 6 at index 6 to maintain sorted order.

数字7的位置被输出

对比bisect_left 和 bisect_right

相同点:
当第二个参数数字x不在第一个参数数组arr中时候,二者都会返回arr中第一个比x大的数的位置

不同点:
当arr中存在x,bisect_left会返回arr中x的最小索引,而bisect_right会返回第一个比x大的数的位置

bisect()

我们查看源码发现:
在这里插入图片描述
bisect就是bisect_right

完整代码

from bisect import bisect_left, bisect, bisect_rightarr = [1, 3, 3, 5, 6, 6, 7, 9, 11]# 在已排序的列表中查找元素 6 的插入位置index = bisect_right(arr, 6)print(f"Insert 6 at index {index} to maintain sorted order.")index = bisect(arr, 6)print(f"Insert 6 at index {index} to maintain sorted order.")index = bisect_left(arr, 6)print(f"Insert 6 at index {index} to maintain sorted order.")

结果:

Insert 6 at index 6 to maintain sorted order.
Insert 6 at index 6 to maintain sorted order.
Insert 6 at index 4 to maintain sorted order.

源码分析

我们先来看 bisect_right 的源码

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 ina[i:] have e > x.  So if x already appears in the list, a.insert(x) willinsert just after the rightmost x already there.Optional args lo (default 0) and hi (default len(a)) bound theslice 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# Use __lt__ to match the logic in list.sort() and in heapqif x < a[mid]: hi = midelse: lo = mid+1return lo

bisect_left 的源码

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 ina[i:] have e >= x.  So if x already appears in the list, a.insert(x) willinsert just before the leftmost x already there.Optional args lo (default 0) and hi (default len(a)) bound theslice 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# Use __lt__ to match the logic in list.sort() and in heapqif a[mid] < x: lo = mid+1else: hi = midreturn lo

我们观察到这两种实现方式主要在于下面两行:
bisect_right:

        if x < a[mid]: hi = midelse: lo = mid+1

bisect_left:

        if a[mid] < x: lo = mid+1else: hi = mid

我们观察到,两段源码都会返回lo,即左边界,所以我们关注一下这两行代码对于左边界的影响:
在bisect_right中,只有当 x=a[mid] or x>a[mid]时,lo才会更新为mid+1,所以最终的lo只可能是第一个大于x的索引
在bisect_left中,当 a[mid] < x时,lo会更新为mid+1,此时我们想要的索引位置必然在mid右侧,所以lo可以为相同的x的第一次出现的位置;同时我们注意到当 a[mid] >= x时,hi=mid,说明当lo取到了相同的数的最左侧时,hi右端点其实会向左平移的,所以lo既可以是数组中第一个大于x的数的索引,也可以是相同的x的最左侧第一个x的索引

这篇关于bisect_left,bisect_right,bisect的用法,区别以源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/510763

相关文章

在Dockerfile中copy和add的区别及说明

《在Dockerfile中copy和add的区别及说明》COPY和ADD都是Dockerfile中用于文件复制的命令,但COPY仅用于本地文件或目录的复制,不支持自动解压缩;而ADD除了复制本地文件或... 目录在dockerfile中,copy 和 add有什么区别?COPY 命令ADD 命令总结在Doc

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock

golang panic 函数用法示例详解

《golangpanic函数用法示例详解》在Go语言中,panic用于触发不可恢复的错误,终止函数执行并逐层向上触发defer,最终若未被recover捕获,程序会崩溃,recover用于在def... 目录1. panic 的作用2. 基本用法3. recover 的使用规则4. 错误处理建议5. 常见错

前端知识点之Javascript选择输入框confirm用法

《前端知识点之Javascript选择输入框confirm用法》:本文主要介绍JavaScript中的confirm方法的基本用法、功能特点、注意事项及常见用途,文中通过代码介绍的非常详细,对大家... 目录1. 基本用法2. 功能特点①阻塞行为:confirm 对话框会阻塞脚本的执行,直到用户作出选择。②

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

解读Pandas和Polars的区别及说明

《解读Pandas和Polars的区别及说明》Pandas和Polars是Python中用于数据处理的两个库,Pandas适用于中小规模数据的快速原型开发和复杂数据操作,而Polars则专注于高效数据... 目录Pandas vs Polars 对比表使用场景对比Pandas 的使用场景Polars 的使用

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录