Python中heapq模块浅析

2023-11-04

Python提供了heapq模块,有利于我们更好的对堆的相关操作进行简化,下面总结我所用到的相关方法。

0 回顾堆的概念

堆就是用数组表示的二叉树,分为大根堆和小根堆,大根堆为堆顶元素最大的堆,小根堆为堆顶元素最小的堆
在这里插入图片描述

1 heappush(heap,item)建立大、小根堆

heapq.heappush()是往堆中添加新值,此时自动建立了小根堆,代码如下

import heapq
a = []   #创建一个空堆
heapq.heappush(a,18)
heapq.heappush(a,1)
heapq.heappush(a,20)
heapq.heappush(a,10)
heapq.heappush(a,5)
heapq.heappush(a,200)
print(a)

输出

[1, 5, 20, 18, 10, 200]

但heapq里面没有直接提供建立大根堆的方法,可以采取如下方法:每次push时给元素加一个负号(即取相反数),此时最小值变最大值,反之亦然,那么实际上的最大值就可以处于堆顶了,返回时再取负即可。

a = []
for i in [1, 5, 20, 18, 10, 200]:
    heapq.heappush(a,-i)
print(list(map(lambda x:-x,a)))

输出

[200, 18, 20, 1, 10, 5]

2 heapify(heap)建立大、小根堆

heapq.heapfy()是以线性时间讲一个列表转化为小根堆

a = [1, 5, 20, 18, 10, 200]
heapq.heapify(a)
print(a)

输出

[1, 5, 20, 18, 10, 200]

用第一节中同样的方法建立大根堆:

a = [1, 5, 20, 18, 10, 200]
a = list(map(lambda x:-x,a))
heapq.heapify(a)
print([-x for x in a])

输出

200, 18, 20, 5, 10, 1]

与第一节所得大根堆相比,虽然二叉树的第三层元素顺序不同,但都符合大根堆的定义

3 heappop(heap)

heapq.heappop()是从堆中弹出并返回最小的值

3.1 利用heappop进行堆排序

堆排序当然也要利用到heappush或者heapify,可参考排序算法总结中的堆排序,这里只贴代码

import heapq
def heap_sort(arr):
    if not arr:
        return []
    h = []  #建立空堆
    for i in arr:
        heapq.heappush(h,i) #heappush自动建立小根堆
    return [heapq.heappop(h) for i in range(len(h))]  #heappop每次删除并返回列表中最小的值

若是从大到小排列,有两种方法:
1)先建立小根堆,然后每次heappop(),此时得到从小大的排列,再reverse
2)利用相反数建立大根堆,然后heappop(-元素)。即push(-元素),pop(-元素)

3.2 普通list的heapop()

普通list(即并没有进行heapify等操作的list),对他进行heappop操作并不会弹出list中最小的值,而是弹出第一个值

>>> a=[3,6,1]
>>> heapify(a)                  #将a变成堆之后,可以对其操作
>>> heappop(a)
1
>>> b=[4,2,5]                   #b不是堆,如果对其进行操作,显示结果如下
>>> heappop(b)                  #按照顺序,删除第一个数值并返回,不会从中挑选出最小的
4
>>> heapify(b)                  #变成堆之后,再操作
>>> heappop(b)
2

4 heappushpop(heap,item)

heapq.heappushpop()是heappush和haeppop的结合,同时完成两者的功能,先进行heappush(),再进行heappop()

>>>h =  [1, 2, 9, 5]
>>> heappop(h)
1
>>> heappushpop(h,4)            #增加4同时删除最小值2并返回该最小值,与下列操作等同:
2                              
>>> h
[4, 5, 9]

5 heapreplace(heap.item)弹出并返回 heap 中最小的一项,同时推入新的 item

heapq.heapreplace()与heapq.heappushpop()相反,先进行heappop(),再进行heappush()
堆的大小不变。 如果堆为空则引发 IndexError。这个单步骤操作比依次执行heappop() + heappush() 更高效,并且在使用固定大小的堆时更为适宜。 pop/push 组合总是会从堆中返回一个元素并将其替换为 item。返回的值可能会比添加的 item 更大。 如果不希望如此,可考虑改用 heappushpop()。 它的 push/pop 组合会返回两个值中较小的一个,将较大的值留在堆中。

>>> a=[]
>>> heapreplace(a,3)            #如果list空,则报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: index out of range
>>> heappush(a,3)
>>> a
[3]
>>> heapreplace(a,2)            #先执行删除(heappop(a)->3),再执行加入(heappush(a,2))
3
>>> a
[2]
>>> heappush(a,5)  
>>> heappush(a,9)
>>> heappush(a,4)
>>> a
[2, 4, 9, 5]
>>> heapreplace(a,6)            #先从堆a中找出最小值并返回,然后加入6
2
>>> a
[4, 5, 9, 6]
>>> heapreplace(a,1)            #1是后来加入的,在1加入之前,a中的最小值是4
4
>>> a
[1, 5, 9, 6]

6 merge(*iterables)

heapq.merge()合并多个堆然后输出
输入的list无序,merge后无序,若输入的list有序,merge后也有序

在这里插入图片描述
heapq.merge()的迭代性质意味着它对所有提供的序列都不会做一次性读取。这意味着可以利用它处理非常长的序列,而开销却非常小

7 nlargest(n , iterbale, key=None) 和nsmallest(n , iterbale, key=None)

获取列表中最大、最小的几个值,key的作用和sorted( )方法里面的key类似

>>>a = [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
>>>heapq.nlargest(5,a)
[25, 20, 15, 10, 8]

>>>b = [('a',1),('b',2),('c',3),('d',4),('e',5)]
>>>heapq.nlargest(1,b,key=lambda x:x[1])
[('e', 5)]

8 复杂度分析

8.1 各方法复杂度

1)heapq.heapify(x): O(n)
2)heapq.heappush(heap, item): O(logn)
3)heapq.heappop(heap): O(logn)

即插入或删除元素时,所有节点自动调整,保证堆的结构的复杂度为O(log n)
4)heapq.nlargest(k,iterable)和nsmallest(k,iterable):O(n * log(t))

8.2 关于排序和取TopN时各方法的快慢比较

在关于排序和取Top N值时,到底使用什么方法最快,python3 cookbook给出了非常好的建议:

1)当要查找的元素个数相对比较小的时候,函数nlargest() 和 nsmallest()。
2)仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用min()和max()函数。
3)如果N的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 (sorted(items)[:N] 或者是 sorted(items)[-N:])。

9 利用heapq模块实现优先队列

# priority 优先级

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0
    def push(self, item, priority):
        # heappush 在队列 _queue 上插入第一个元素
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1
    def pop(self):
        # heappop 在队列 _queue 上删除第一个元素
        return heapq.heappop(self._queue)[-1]

class Item:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return ‘Item({!r}).format(self.name)

代码解读:

调用push()方法,实现将列表转化为堆数据

插入的是元组,元组大小比较是从第一个元素开始,第一个相同,再对比第二个元素,我们这里采用的方案是如果优先级相同,那么就根据第二个元素,谁先插入堆中,谁的index就小,那么它的值就小

heapq.heappop() 方法得到,该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素。

测试:

q = PriorityQueue()

q.push(Item(‘foo’), 1)

q.push(Item(‘bar’), 5)

q.push(Item(‘spam’), 4)

q.push(Item(‘grok’), 1)

print(q.pop())

print(q.pop())

print(q.pop())

输出:

Item(‘bar’)

Item(‘spam’)

Item(‘foo’)

参考文献

https://blog.csdn.net/minxihou/article/details/51857518
https://github.com/qiwsir/algorithm/blob/master/heapq.md
https://rookiefly.cn/detail/225
https://www.jianshu.com/p/45a6717bf093
https://love.ranshy.com/heapq-%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/
http://www.shuang0420.com/2016/12/27/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95%20–%20%E5%A0%86/
http://landcareweb.com/questions/44452/heapqku-zhong-han-shu-de-shi-jian-fu-za-du-shi-duo-shao

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python中heapq模块浅析 的相关文章

随机推荐

  • json/xml/schema

    JSON JSON是JavaScript Object Notation的缩写 是一种轻量级的数据交换格式 是理想的接口数据交换语言 官网 https www json org json en html 工作json请求体 json字符串
  • docker cp拷贝文件_Docker - A焕然一新

    Docker的基本组成 镜像 容器 仓库 镜像 image 就像是一个模板 可以通过这个模板来创建容器服务 通过镜像可以创建多个容器 最终服务运行或者项目运行就在容器中 容器 container Docker利用容器技术 独立运行一个或者一
  • [附源码]java毕业设计网上博物馆设计

    项目运行 环境配置 Jdk1 8 Tomcat7 0 Mysql HBuilderX Webstorm也行 Eclispe IntelliJ IDEA Eclispe MyEclispe Sts都支持 项目技术 SSM mybatis Ma
  • 基于wsl2在windows下使用docker应用

    wsl2重启 管理员权限打开powershell 然后执行下面命令 powershell切换为管理员权限 Start Process powershell Verb runAs 关闭服务 net stop LxssManager 重启服务
  • 基于数据库版本的分布式定时任务调度中心

    github调度中心源码地址 https github com yomea timer task scheduler github业务端源码地址 https github com yomea task scheduler starter g
  • 'sqlplus' 不是内部或外部命令,也不是可运行的程序

    在DOS下sqlplus exp imp命令提示 不是内部或外部命令 也不是可运行的程序或批处理文件 首先 确认oracle安装路径下的根目录 oracle home bin目录下的sqlplus exe imp exe exp exe等可
  • GD32F103RC的ADC采样值偏大

    在最近的一个项目中 使用了GD32做控制器 初期调试ADC很顺利 但后期将代码组合后发现ADC的采样值都偏大了 经过反复调试 发现和一个引脚PB0有关 只要将PB0初始化或者外部有电路将电平拉低 PC0 PC1 PC2的ADC采样值就会变大
  • C++之shared_from_this用法以及类自引用this指针陷阱

    C 系列文章目录 文章目录 C 系列文章目录 前言 一 为什么需要enable shared from this 二 enable shared from this用法 总结 前言 shared ptr实现原理 shared ptr 从 P
  • uni-app 收获地址API报错:chooseAddress:fail the api need to be declared in …e requiredPrivateInfos field in

    一 代码 选择收获地址 async chooseAddress const res await uni chooseAddress catch err gt err console log res res 二 报错信息 三 原因 这是由于微
  • uniapp中uni.showToast最多显示多少个汉字?

    在 uni showToast 中 最多可以显示 14 个汉字 超出的就会被隐藏 而且隐藏的效果根据手机效果还不一样 有的是 有的直接没了 这是由于 uni showToast 会在屏幕上显示一个浮动的提示框 提示框的大小是有限的 所以最多
  • 2023-ChatGPT解析及使用方法

    什么是Chat GPT 我们能用它来干什么 Chat GPT是一款基于人工智能技术的自然语言处理模型 由OpenAI团队开发 它能够通过机器学习技术从海量文本数据中学习语言知识 实现自然语言生成 对话生成和语言理解等功能 使得机器能够更加智
  • DELETE语句

    DELETE 语句用于删除表中的行 语法 DELETE FROM table name WHERE some column some value 示例 DELETE FROM Websites WHERE name 百度 AND count
  • pytorch实战-图像分类(一)(数据预处理)

    目录 1 导入各种库 2 数据预处理 2 1数据读取 2 2图像增强 3 构建数据网络 3 1网络构建 3 2读取标签对应的名字 4 展示数据 4 1数据转换 4 2画图 5 模型训练 1 导入各种库 上代码 import os impor
  • ESP32 Https server 错误Header fields are too long for server to interpret

    这个错误的根源是浏览器发送的请求头文件过于长 esp32 header fields are too long issue 给出了解决方案 修改sdkconfig文件中的CONFIG HTTPD MAX REQ HDR LEN 将其设置为更
  • DS证据理论

    1 基本概念 假设空间 识别框架 对于全域X X A B 那么假设空间为 空 A B AB Mass函数和BPA mass函数给假设空间每一个假设都分配了概率 我们称为基本概率分配 BPA Basic Probability Assignm
  • [设计模式] 浅谈SOLID设计原则

    目录 单一职责原则 开闭原则 里氏替换原则 接口隔离原则 依赖倒转原则 SOLID是一个缩写词 代表以下五种设计原则 单一职责原则 Single Responsibility Principle SRP 开闭原则 Open Closed P
  • VC++6.0的使用技巧

    1 建立工程 一定要创建window32位控制台应用 Win32 console Application 2 创建新文件 文件 新建 文件 源文件或头文件 3 如果不想要的文件 File View gt XXX files gt Sourc
  • 量子力学与自由意志

    第一个观点 是有造物主存在的 人不是偶然出险的 第二个观点 人是否具备自由意志 人可以违背生物定律做出自己的选择 量子力学的微观实验 因果链可以倒置 唯物主义与唯心主义到底谁是对的 熵增定律 普朗克 爱因斯坦 波尔 杨老 世界是非连续的 粒
  • [520]pandas(ix & iloc &loc)区别

    loc 通过行标签索引行数据 iloc 通过行号索引行数据 ix 通过行标签或者行号索引行数据 基于loc和iloc 的混合 举例说明 1 分别使用loc iloc ix 索引第一行的数据 coding utf 8 import panda
  • Python中heapq模块浅析

    Python提供了heapq模块 有利于我们更好的对堆的相关操作进行简化 下面总结我所用到的相关方法 文章目录 0 回顾堆的概念 1 heappush heap item 建立大 小根堆 2 heapify heap 建立大 小根堆 3 h