前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python中的堆排序与优先队列

Python中的堆排序与优先队列

作者头像
子润先生
修改于 2021-06-18 02:50:57
修改于 2021-06-18 02:50:57
4740
举报

对数据进行排序是一个很常见的需求,但有时候我们并不需要对完整的数据进行排序,只需要排前几的数据,也就是经典的 Top-K 问题。

Top-K 问题的经典解法有两种:一种是脱胎于快速排序(Quick Sort)的快速选择(Quick Select)算法,核心思路是在每一次Partion操作后下一次递归只操作前K项数据。另一种是基于堆排序的方法。

Python 中有两个标准库可以原生的支持堆排序(优先队列),分别是heapqPriorityQueue(queue)

heapq

heapq标准库提供了一些工具函数用来对list对象实现二叉堆的各种操作(就地修改list对象)。简单的用法如下:

建堆

123456

import heapq# 可以用过random.shuffle函数创造乱序数组arr = [4, 0, 3, 1, 6, 5, 9, 7, 8, 2]heapq.heapify(arr)assert arr == [0, 1, 3, 4, 2, 5, 9, 7, 8, 6]

获取堆顶元素

12

assert heapq.heappop(arr) == 0assert arr == [1, 2, 3, 4, 6, 5, 9, 7, 8]

插入新元素

12

heapq.heappush(arr, 11)assert arr == [1, 2, 3, 4, 6, 5, 9, 7, 8, 11]

heapq也提供了直接获取nlargestnsmallest函数,并且这两个函数并不会就地修改原数据。

1234

arr = [4, 0, 3, 1, 6, 5, 9, 7, 8, 2]assert heapq.nlargest(5, arr) == [9, 8, 7, 6, 5]assert arr == [4, 0, 3, 1, 6, 5, 9, 7, 8, 2]assert heapq.nsmallest(5, arr) == [0, 1, 2, 3, 4]

queue.PriorityQueue

queue标准库为 Python 代码提供了原生线程安全的队列实现。queue.PriorityQueue则是 Python 原生的优先队列实现,相比heapq有着更直观易用的接口。

创建优先队列

12345678

from queue import PriorityQueuepq = PriorityQueue()arr = [4, 0, 3, 1, 6, 5, 9, 7, 8, 2]for num in arr: pq.put(num)

获取队首元素

12

while not pq.empty(): assert pq.get() == 0

对比

heapq标准库是专门用来做堆排序相关操作的,而PriorityQueue类毕竟继承于queue.Queue,适用于多线程通信场景。两者的效率还是有着不小差距的。

我们以 LeetCode 973(最接近原点的 K 个点)为例,分别用heapqPriorityQueue实现,比较一下二者的运行效率。

题目描述

973. 最接近原点的 K 个点

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。

示例 1

输入:points = [[1,3],[-2,2]], K = 1 输出:[[-2,2]] 解释: (1, 3) 和原点之间的距离为 sqrt(10), (-2, 2) 和原点之间的距离为 sqrt(8), 由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。 我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。

示例 2

输入:points = [[3,3],[5,-1],[-2,4]], K = 2 输出:[[3,3],[-2,4]] (答案 [[-2,4],[3,3]] 也会被接受。)

提示:

1 <= K <= points.length <= 10000 -10000 < points[i][0] < 10000 -10000 < points[i][1] < 10000

生成测试数据

12345

from random import randintdef genPoints(n:int = 100): return [(randint(0, 100), randint(0, 100)) for _ in range(n)]points = genPoints(1_0000)less_points = genPoints(100)

heapq实现

123456789101112131415161718

import heapqfrom typing import Listdef distance(point: List[int]): return point[0] ** 2 + point[1] ** 2class Solution: def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]: distances = [(distance(point), point) for point in points] return [e[1] for e in heapq.nsmallest(K, distances)]solution = Solution()%timeit solution.kClosest(points, 100)# 6.79 ms ± 181 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

PriorityQueue实现

12345678910111213141516171819202122

from queue import PriorityQueuefrom typing import Listdef distance(point: List[int]): return point[0] ** 2 + point[1] ** 2class Solution: def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]: pq = PriorityQueue() for point in points: pq.put((distance(point), point), block=False) ret = [] while not pq.empty(): ret.append(pq.get()[1]) return retsolution = Solution()%timeit solution.kClosest(points,100)# 52.2 ms ± 1.26 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

我们可以看到heapq版本比PriorityQueue版本快接近一个数量级,并且代码也更精简。

这也说明了我们要在合适的地方使用合适的工具。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python中的堆排序与优先队列
对数据进行排序是一个很常见的需求,但有时候我们并不需要对完整的数据进行排序,只需要排前几的数据,也就是经典的 Top-K 问题。
杜逸先
2021/06/09
1.3K0
Python heapq priority queue
Python 中内置的 heapq 库和 queue 分别提供了堆和优先队列结构,其中优先队列 queue.PriorityQueue 本身也是基于 heapq 实现的,因此我们这次重点看一下 heapq 。
用户7886150
2020/12/24
6170
Python堆排序之heapq
heapq模块实现了Python中的堆排序,并提供了有关方法。让用Python实现排序算法有了简单快捷的方式。
小歪
2018/12/24
1.2K0
LeetCode 973. 最接近原点的 K 个点(排序/优先队列/快排)
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
Michael阿明
2020/07/13
6970
Python应用——优先队列与heapq
heapq的全写是heap queue,是堆队列的意思。这里的堆和队列都是数据结构,在后序的文章当中我们会详细介绍,今天只介绍heapq的用法,如果不了解heap和queue原理的同学可以忽略,我们并不会深入太多,会在之后的文章里详细阐述。
TechFlow-承志
2020/03/05
9900
Python应用——优先队列与heapq
Leetcode 【739、946、973】
这道题是给一个温度列表,重新生成一个列表:对应位置是需要再等待多久温度才会升高超过该日的天数。
echobingo
2019/07/01
4300
python下实现二叉堆以及堆排序
堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序。堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势。
Ryan_OVO
2023/10/18
1770
Leetcode | 第5节:排序方法的设计,堆,堆排序,快速排序
这一节我们来继续讨论排序算法所延伸出的一些题目。如果有空的话,还会说一些堆,也就是优先队列的一些比较经典的题目。
学弱猹
2021/08/10
7880
Leetcode | 第5节:排序方法的设计,堆,堆排序,快速排序
LeetCode 973 K Closest Points to Origin
We have a list of points on the plane. Find the K closest points to the origin (0, 0).
Yano_nankai
2019/02/25
4690
堆排序与优先队列
(二叉)堆物理上是一个数组,逻辑上是一棵完全二叉树,树上的每一个结点对应数组中的一个元素。 设表示堆的数组 ,其包含两个属性:
hotarugali
2022/03/01
3320
排序|优先队列不知道,先看看堆排序吧
在个人的专栏中,其他排序陆陆续续都已经写了,而堆排序迟迟没有写,趁着国庆假期的尾声,把堆排序也写一写。
bigsai
2020/10/22
3430
排序|优先队列不知道,先看看堆排序吧
python队列、缺省字典、排序字典
python队列、缺省字典、排序字典 import heapq class PriorityQueue: def __init__(self): self._queue = [] self._index = 0 def push(self, item, priority): heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1
python与大数据分析
2022/03/11
2.5K0
python队列、缺省字典、排序字典
python 堆和优先队列的使用
python里面的堆是通过在列表中维护堆的性质实现的。这一点与C++中heap一系列的算法类似,底层是通过堆vector的维护获取堆的性质。 python堆的部分API,其他API查阅文档python_heap_API和 heapq的源代码
py3study
2020/01/08
1.3K0
【JavaScript 算法】堆排序:优先队列的实现
堆排序的基本思想是将待排序的数组构建成一个最大堆或最小堆,然后通过堆的删除操作将堆顶元素逐个取出,得到一个有序序列。
空白诗
2024/07/20
2510
【JavaScript 算法】堆排序:优先队列的实现
PHP堆和堆排序
我们看根节点,值100大于两个子节点19和36。对于19来说,该值大于17和3。其他节点也适用相同的规则。我们可以看到,这棵树没有完全排序。但重要的事实是我们总能找到树的最大值或最小值,在许多特殊的情况下这是非常有用的。
猿哥
2019/07/24
6490
漫画:美团面试题(TOPK:求第K个最大的元素)
这个题目的变形很多,比如找 "前 K 个高频元素"、 "数据流中的第K大元素" 、"最接近原点的 K 个值" 等等等等。
程序员小浩
2020/03/30
2.7K0
漫画:美团面试题(TOPK:求第K个最大的元素)
八十四、堆排序解决TopK问题
题目是这样的:假设,我们想在大量的数据,如 100 亿个整型数据中,找到值最大的 K 个元素,K 小于 10000。对此,你会怎么做呢?
润森
2022/08/17
6930
八十四、堆排序解决TopK问题
基于event 实现的线程安全的优先队列(python实现)
event 事件是个很不错的线程同步,以及线程通信的机制,在python的许多源代码中都基于event实现了很多的线程安全,支持并发,线程通信的库
Ryan_OVO
2023/10/18
2090
基于event 实现的线程安全的优先队列(python实现)
优先队列
和入队顺序无关,总是优先级最高的元素优先出队。 如果说栈是每次输出最近进入的元素,队列是每次输出最早进入的元素,那么优先队列就是每次输出优先级最高的元素。
六月丶
2022/12/26
4780
优先队列
理解堆和优先队列
数据结构中的堆区别于内存分配的堆,我们说的用于排序的堆是一种表示元素集合的结构,堆是一种二叉树。
C语言与CPP编程
2020/12/02
1K0
理解堆和优先队列
相关推荐
Python中的堆排序与优先队列
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档