python中的bisect模块与二分查找详情

目录
  • 1.bisect模块概述
  • 2.bisect模块的函数详解
    • 2.1 bisect.bisect*()方法
    • 2.2 bisect.insort*()方法
  • 3.python中的二分查找
    • 3.1 标准的二分查找
    • 3.2 查找第一个>=target的元素索引
    • 3.3 查找第一个>target的元素索引
  • 4.二分查找的变形与 bisect 模块的关系

1.bisect模块概述

bisect是python的内置模块, 用于有序序列的插入和查找。 插入的数据不会影响列表的排序, 但是原有列表需要是有序的, 并且不能是倒序.

Bisect模块提供的函数有:

  • bisect.bisect_left(a,x, lo=0, hi=len(a))
  • bisect.bisect_right(a,x, lo=0, hi=len(a))
  • bisect.bisect(a, x,lo=0, hi=len(a))
  • bisect.insort_left(a,x, lo=0, hi=len(a))
  • bisect.insort_right(a,x, lo=0, hi=len(a))
  • bisect.insort(a, x,lo=0, hi=len(a))

2.bisect模块的函数详解

2.1 bisect.bisect*()方法

  • bisect.bisect_left(a,x,lo=0,hi=len(a),*,key=None)

在有序数组a中[lo,hi]区间内查找x插入的位置,返回的是索引值。如果a中有跟x相同的元素,则x插入的位置是左边,key指定了一个单参数的方法,该方法的返回值作为与k比较的基准。

值得注意的是,key参数是3.10版本以后才添加的功能

  • bisect.bisect_right(a,x,lo=0,hi=len(a),*,key=None),在有序数组a中[lo,hi]区间内查找x插入的位置,返回索引值。如果a中有跟x相同的元素,则x插入的位置是右边。
  • bisect.bisect(a,x,lo=0,hi=len(a),*,key=None),同bisect_right
# bisect_left Vs. bisect (bisect_right)
import bisect

nums = [1, 2, 2, 4]
i, j = bisect.bisect_left(nums, 2), bisect.bisect(nums, 2)
print(i)  # 输出1
print(j)  # 输出3

可见,针对上面给出的数组,想要插入2,使用bisect_left返回的索引值是1,使用bisect(bisect_right)返回的索引值是3。如果指定了lo和hi的话,那么返回的就是在这个范围内的索引。如下面的例子所示。

# 指定lo和hi
import bisect

nums = [1, 2, 2, 2, 2, 4]
i = bisect.bisect_left(nums, 2, 3)
print(i)  # 输出为3

如果不指定lo=3的话,返回的索引应该是1。指定lo=3后,返回的索引为3。

关键字key指定了一个方法,这个方法会接受当前数组中的中间值mid(因为二分查找就是从中间值开始的)作为其参数,然后返回一个值val,val用于跟x比较。

# 指定key值
import bisect

nums = [1, 2, 3, 4, 6, 8]

def divide(mid):
    print('mid: ' + str(mid))
    return mid // 2

i = bisect.bisect_left(nums, 5, key=divide)
print(i)

上面的例子中定义了一个divide方法。那么bisect_left方法的执行顺序是这样的:

  • nums中的中间值mid=4, divide(mid)方法返回值为2
  • 5>2,则查找nums的右子数组,即[6,8]
  • [6,8]的中间值是mid=8, divide(mid)方法返回值为4
  • 5>4,则继续查找右子数组,可是已经没有右子数组了,则返回索引值为6.

2.2 bisect.insort*()方法

  • bisect.insort_left(a,x,lo=0,hi=len(a),*,key=None),在有序数组a中[lo,hi]区间内查找x插入的位置,返回的是索引值。如果a中有跟x相同的元素,则x插入的位置是最左边,key指定了一个单参数的方法,该方法的返回值作为与k比较的基准。
  • bisect.insort_right(a,x,lo=0,hi=len(a),*,key=None),在有序数组a中[lo,hi]区间内查找x插入的位置,返回索引值。如果a中有跟x相同的元素,则x插入的位置是最右边。
  • bisect.insort(a,x,lo=0,hi=len(a),*,key=None),同insort_right。
# bisect.insort_left
import bisect

nums = [1, 2, 3, 4, 6, 8]
bisect.insort_left(nums, 5)
print(nums)
# [1, 2, 3, 4, 5, 6, 8]

值得注意的是,insort方法中的key和bisect方法中的key指定的方法针对的对象是不同的

# bisect.insort_left with key
import bisect

nums = [1, 2, 3, 4, 6, 8]
def divide(mid):
    print('mid: ' + str(mid))
    return mid // 2
bisect.insort_left(nums, 5, key=divide)

可见,key指定的方法的参数是针对x的。也就是说insort_left方法的执行顺序是这样的:

  • mid=x=5,返回的值是2,也就是divide(x)
  • mid是数组的中间值,即mid=4, divide方法返回的值是2
  • divide(x)==2,则查找左子数组
  • 中间值为2,mid=2, divide方法返回的值是1
  • divide(x)>1,则查找右子数组
  • 中间值为3,mid=3, divide方法的返回值是1
  • divide(x)>1,则查找右子数组
  • 没有右子数组了,则插入位置的索引为3,得到了插入5之后的数组为[1,2,3,5,4,6,8]

3.python中的二分查找

3.1 标准的二分查找

class BinarySearch:
    # 标准的二分查找,找不到返回-1
    def binsearch(self, nums, target):
        lo, hi = 0, len(nums) - 1
        while lo <= hi:
            mid = lo + (hi - lo) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                hi = mid - 1
            else:  # nums[mid] < target:
                lo = mid + 1
        return -1

3.2 查找第一个>=target的元素索引

class BinarySearch:
    # 查找第一个>=target的元素索引,找不到返回数组长度
    def lowerbound(self, nums, target):
        lo, hi = 0, len(nums) - 1
        pos = len(nums)  # 找不到
        while lo < hi:
            mid = lo + (hi - lo) // 2
            if nums[mid] >= target:
                hi = mid
            else:  # nums[mid] < target:
                lo = mid + 1
        if nums[lo] >= target:  # lo:要找的元素索引
            pos = lo
        return pos

3.3 查找第一个>target的元素索引

class BinarySearch:
    # 查找第一个>target的元素索引,找不到返回数组长度
    def upperbound(self, nums, target):
        lo, hi = 0, len(nums) - 1
        pos = len(nums)  # 找不到
        while lo < hi:
            mid = lo + (hi - lo) // 2
            if nums[mid] > target:
                hi = mid
            else:  # nums[mid] <= target:
                lo = mid + 1
        if nums[lo] > target:  # lo:要找的元素索引
            pos = lo
        return pos

4.二分查找的变形与 bisect 模块的关系

  • 二分查找中的 lowerbound(nums, target) 等价于 bisect.bisect_left(a,x, lo=0, hi=len(a))
  • 二分查找中的upperbound(nums, target) 等价于 bisect.bisect_right(a,x, lo=0, hi=len(a)) 或者bisect.bisect(a,x, lo=0, hi=len(a))

到此这篇关于python中的bisect模块与二分查找详情的文章就介绍到这了,更多相关python bisect模块 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python实现二分查找与bisect模块详解

    前言 其实Python 的列表(list)内部实现是一个数组,也就是一个线性表.在列表中查找元素可以使用 list.index() 方法,其时间复杂度为O(n) .对于大数据量,则可以用二分查找进行优化. 二分查找要求对象必须有序,其基本原理如下: 1.从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束: 2.如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较. 3.如果在某一步骤数组为空,则代表找不到. 二分查找也

  • Python二分查找详解

    先来看个实例 #!/usr/bin/env python import sys def search2(a,m): low = 0 high = len(a) - 1 while(low <= high): mid = (low + high)/2 midval = a[mid] if midval < m: low = mid + 1 elif midval > m: high = mid - 1 else: print mid return mid print -1 return -

  • Python中bisect的用法

    本文实例讲述了Python中bisect的用法,是一个比较常见的实用技巧.分享给大家供大家参考.具体分析如下: 一般来说,Python中的bisect用于操作排序的数组,比如你可以在向一个数组插入数据的同时进行排序.下面的代码演示了如何进行操作: import bisect import random random.seed(1) print('New pos contents') print('-----------------') l=[] for i in range(1,15): r=r

  • Python中bisect的用法及示例详解

    bisect是python内置模块,用于有序序列的插入和查找. 查找: bisect(array, item) 插入: insort(array,item) 查找 import bisect a = [1,4,6,8,12,15,20] position = bisect.bisect(a,13) print(position) # 用可变序列内置的insert方法插入 a.insert(position,13) print(a) 输出: 5 [1, 4, 6, 8, 12, 13, 15, 2

  • Python二分查找+字符串模板+textwrap模块,

    目录 二分查找 字符串模板 textwrap 模块 按照空格统计词组个数 用 “0” 填充字符串 前言: 这个系列的专栏是为了保持 Python 手感而创建的,也可以用来学习 Python,因为存在知识跨越难度,所以先学习滚雪球系列为佳. 二分查找 问题场景 在一个升序的数组中(其实就是一个只有整数的列表),查找一个目标数的下标,不存在返回 -1 . 解决思路 因为数组是升序的,所以二分查找就能落地了 先取出数组中的中间值,与目标数比较大小,确定一半的范围 然后重复上述步骤不断缩小范围即可. 编

  • Python中bisect的使用方法

    Python中列表(list)的实现其实是一个数组,当要查找某一个元素的时候时间复杂度是O(n),使用list.index()方法,但是随着数据量的上升,list.index()的性能也逐步下降,所以我们需要使用bisect模块来进行二分查找,前提我们的列表是一个有序的列表. 递归二分查找和循环二分查找 def binary_search_recursion(lst, val, start, end): if start > end: return None mid = (start + end

  • Python bisect模块原理及常见实例

    1. 模块介绍 1. bisect模块为内置标准库,它实现了二分法查找算法(只要提到二分法查找,应该优先想到此模块) 2. 主要包含有两个函数:bisect函数(查找元素)和insort函数(插入元素). 2. 常用方法介绍 场景1:已知一个有序列表,查找目标元素的位置索引 import bisect # 已知一个有序序列 ordered_list = [23, 34, 59, 78, 99] des_element = 21 res = bisect.bisect(ordered_list,

  • python中bisect模块用法实例

    本文实例讲述了python中bisect模块用法,分享给大家供大家参考. 具体方法分析如下: 这个模块只有几个函数,一旦决定使用二分搜索时,立马要想到使用这个模块. 示例代码如下: import bisect L = [1,3,3,6,8,12,15] x = 3 x_insert_point = bisect.bisect_left(L,x)#在L中查找x,x存在时返回x左侧的位置,x不存在返回应该插入的位置..这是3存在于列表中,返回左侧位置1 print x_insert_point x_

  • python二分查找算法的递归实现方法

    本文实例讲述了python二分查找算法的递归实现方法.分享给大家供大家参考,具体如下: 这里先提供一段二分查找的代码: def binarySearch(alist, item): first = 0 last = len(alist)-1 found = False while first<=last and not found: midpoint = (first + last)//2 if alist[midpoint] == item: found = True else: if ite

  • python中的bisect模块与二分查找详情

    目录 1.bisect模块概述 2.bisect模块的函数详解 2.1 bisect.bisect*()方法 2.2 bisect.insort*()方法 3.python中的二分查找 3.1 标准的二分查找 3.2 查找第一个>=target的元素索引 3.3 查找第一个>target的元素索引 4.二分查找的变形与 bisect 模块的关系 1.bisect模块概述 bisect是python的内置模块, 用于有序序列的插入和查找. 插入的数据不会影响列表的排序, 但是原有列表需要是有序的

  • Python中如何添加自定义模块

    一般来说,我们会将自己写的Python模块与python自带的模块分开存放以达到便于维护的目的.那么如何在Python中添加自定义的模块呢? 在解答这个问题之前,我们首先要明确两点: 1.严格区分包(package)和文件夹.包的定义就是包含__init__.py的文件夹.如果没有__init__.py,那么就是普通的文件夹. 2.模块导入写法,注意只要包路径,不要文件夹路径. Python 运行环境在查找库文件时是对 sys.path 列表进行遍历,如果我们想在运行环境中注册新的类库,主要有以

  • Python中使用select模块实现非阻塞的IO

    Socket的英文原义是"孔"或"插座".作为BSD UNIX的进程通信机制,取后一种意思.通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.在Internet上的主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务.Socket正如其英文原意那样,像一个多孔插座.一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110

  • 深入理解python中的select模块

    简介 Python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统) select方法 进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生时,进程被阻塞:当一个或者多个文件描述符事件发生时,进程被唤醒. 当我们调用select()时: 1.上下文切换转换为内核态 2.将fd从用户空间复制到内核空

  • 使用Python中的tkinter模块作图的方法

    python简述: Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.自从20世纪90年代初Python语言诞生至今,它逐渐被广泛应用于处理系统管理任务和Web编程.Python[1]已经成为最受欢迎的程序设计语言之一.2011年1月,它被TIOBE编程语言排行榜评为2010年度语言.自从2004年以后,python的使用率是呈线性增长. tkinter模块介绍 tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以

  • python中利用h5py模块读取h5文件中的主键方法

    如下所示: import h5py import numpy as np #HDF5的写入: imgData = np.zeros((2,4)) f = h5py.File('HDF5_FILE.h5','w') #创建一个h5文件,文件指针是f f['data'] = imgData #将数据写入文件的主键data下面 f['labels'] = np.array([1,2,3,4,5]) #将数据写入文件的主键labels下面 f.close() #关闭文件 #HDF5的读取: f = h5

  • 详解python中的hashlib模块的使用

    hashlib hashlib主要提供字符加密功能,将md5和sha模块整合到了一起,支持md5,sha1, sha224, sha256, sha384, sha512等算法 hashlib模块 #哈希算法也叫摘要算法,相同的数据始终得到相同的输出,不同的数据得到不同的输出. #(1)哈希将不可变的任意长度的数据,变成具有固定长度的唯一值 #(2)字典的键值对映射关系是通过哈希计算的,哈希存储的数据是散列(无序) # 应用场景:在需要效验功能时使用  用户密码的 => 加密,解密  相关效验的

  • 在Python中合并字典模块ChainMap的隐藏坑【推荐】

    在Python中,当我们有两个字典需要合并的时候,可以使用字典的 update 方法,例如: a = {'a': 1, 'b': 2} b = {'x': 3, 'y': 4} a.update(b) print(a) 运行效果如下图所示: 然而,这个方法有一个问题--它会改变其中一个字典.如果我们不想改变原有的两个字典,那么我们必需要单独再创建一个字典: a = {'a': 1, 'b': 2} b = {'x': 3, 'y': 4} c = dict(a) c.update(b) prin

  • 对python中的logger模块全面讲解

    logging模块介绍 Python的logging模块提供了通用的日志系统,熟练使用logging模块可以方便开发者开发第三方模块或者是自己的Python应用.同样这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP.GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式.下文我将主要介绍如何使用文件方式记录log. logging模块包括logger,handler,filter,formatter这四个基本概念. logging模块与log4

  • 对python中使用requests模块参数编码的不同处理方法

    python中使用requests模块http请求时,发现中文参数不会自动的URL编码,并且没有找到类似urllib (python3)模块中urllib.parse.quote("中文")手动URL编码的方法.研究了半天发现requests模块对中文参数有3种不同的处理方式. 一.requests模块自动URL编码参数 要使参数自动URL编码,需要将请求参数以字典的形式定义,如下demo: import requests proxy = {"http":"

随机推荐