堆排序 之实现最小的K个数

目录

1、方式一:通过自定义实现建堆和堆化操作

2、方式二:借助模块heapq实现

2.1、模块heapq的基本使用

2.2、使用heapq实现最小的k个数

3、堆在实际项目的应用

实现语言:Python 3.9

题目来源:牛客

分析:

  • 要找到最小的k个元素,只需要准备k个数字,之后每次遇到一个数字能够快速的与这k个数字中最大的值比较(大顶堆),每次将最大的值替换掉,那么最后剩余的就是k个最小的数字了。

为什么不是与k个元素中的最小值(小顶堆)进行比较呢?

  • 我们使用示例分析为什么使用小顶堆就不能实现,对于[4, 5, 1, 6, 2, 7, 3, 8] k = 4 建立小顶堆,建立的小顶堆为[1, 5, 4, 6] 堆顶元素为1,此时使用元素2和堆顶元素比较,比堆顶元素大,不加入堆顶;那么这样可见最后得到的结果一定不是最小的k个元素,所以不能使用小顶堆。

实现步骤:

  • 1:利用input数组中前k个元素,构建一个大小为k的大顶堆,堆顶为这k个元素的最大值。
  • 2:对于后续的元素,依次比较其与堆顶的大小,若是比堆顶小,则堆顶弹出,再将新数加入堆中,直至数组结束,保证堆中的k个最小。
  • 3:最后将堆顶依次弹出即是最小的k个数。

实现方式:

  • 方式一:通过自定义实现建堆和堆化操作
  • 方式二:借助Python模块heapq实现

1、方式一:通过自定义实现建堆和堆化操作

class Solution:def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:# write code here# 建堆(从最后一个非叶子节点到根节点建堆)def buildHeap(a, n):i = n//2 - 1while i >=0:heapify(a, n, i)i = i - 1# 堆化(从上到下)def heapify(a, n, i):while True:maxPos = i# 和左子节点比较if i*2 + 1 <= n and a[i] < a[i*2+1]:maxPos = i*2 + 1# 和右子节点比较if i*2 + 2 <= n and a[maxPos] < a[i*2+2]:maxPos = i*2 + 2if maxPos == i:break# 交换节点a[i], a[maxPos] = a[maxPos], a[i]i = maxPos# 特殊情况处理if len(input) == 0 or len(input) <= k:return input# 先前k个数据建堆buildHeap(input, k)# 后面的节点依次和堆顶元素比较# 如果比堆顶元素小,将该元素加入堆顶,然后从堆顶开始堆化for i in range(k, len(input)):if input[0] > input[i]:# 该元素和堆顶元素交换input[0], input[i] = input[i], input[0]# 从堆顶元素开始从上往下堆化heapify(input, k, 0)return input[:k]

2、方式二:借助模块heapq实现

  • 注意:heapq模块默认建立的是小顶堆,所以需要借助这个特性自定义实现大顶堆

2.1、模块heapq的基本使用

import heapq# 创建一个空堆
heap = []# 往堆中添加元素
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 4)
heapq.heappush(heap, 1)
heapq.heappush(heap, 5)
# 弹出最小元素
print(heapq.heappop(heap))  # 输出 1
print(heapq.heappop(heap))  # 输出 1# 弹出最小元素并加入新元素
print(heapq.heapreplace(heap, 2))  # 输出 2# 将列表转化为堆
heap = [5, 8, 3, 0, 2]
heapq.heapify(heap)
print(heap)  # 输出 [0, 2, 3, 8, 5]# 获取最大的两个元素
print(heapq.nlargest(2, heap))  # 输出 [8, 5]
# 获取最小的两个元素
print(heapq.nsmallest(2, heap)) # 输出 [0, 2]

2.2、使用heapq实现最小的k个数

import heapq
class Solution:def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:# 特殊情况处理if len(input) == 0 or len(input) < k or k == 0:return []# 自定义实现建立大顶堆def my_max_heapify(iterable):# 原理是对输入数据取反,这样建立的小顶堆,取数的时候进行取反即是大顶堆max_heap = [(-x, x) for x in iterable]# 建堆heapq.heapify(max_heap)# 返回max_heap中元祖数据的第二个,忽略第一个数据return [x for (_, x) in max_heap]# 前k个数据建堆max_heap = my_max_heapify(input[:k])# 后面的数据依次与堆顶元素比较for i in range(k, len(input)):if max_heap[0] > input[i]:# 弹出堆顶元素,加入新元素heapq.heapreplace(max_heap, input[i])# 再次对数据进行堆化max_heap = my_max_heapify(max_heap)return max_heap

3、堆在实际项目的应用

  1. 优先级队列:堆常常被用来实现优先级队列。在优先级队列中,元素被赋予一个优先级,并且总是按照优先级的顺序被处理。最大堆或最小堆可以根据需要用来实现具有最高或最低优先级元素始终位于队列头部的优先级队列。这种数据结构在任务调度、网络路由和事件处理等场景中非常有用。
  2. 堆排序:堆排序是一种基于堆的高效排序算法,其时间复杂度为O(nlogn)。它通过构建最大堆或最小堆,然后不断地取出堆顶元素(最大或最小值)并将其与堆的最后一个元素交换,然后重新调整堆的结构,直到整个数组有序。堆排序在处理大数据集时非常有效。
  3. 数据流中的Top K问题:在数据流处理中,经常需要找到数据流中最大的K个元素或最小的K个元素。这可以通过使用最大堆或最小堆来实现。具体做法是将数据流中的元素逐个插入堆中,并保持堆的大小为K。如果新插入的元素比堆顶元素(最大或最小)更大(或更小),则删除堆顶元素并插入新元素。这样,堆中始终保存着数据流中最大的K个元素或最小的K个元素。
  4. 合并有序文件:当需要合并多个有序文件为一个有序文件时,可以使用堆来实现。具体做法是将每个文件的第一个元素放入一个最小堆中,然后每次从堆中取出最小的元素并写入结果文件,然后从该元素所在的文件中取出下一个元素并重新放入堆中。重复这个过程直到所有文件都被处理完毕。
  5. 高性能定时器:在高性能定时器中,可以使用最小堆来管理定时任务。具体做法是将每个定时任务按照其触发时间放入最小堆中,然后每次从堆中取出触发时间最小的任务并执行。这样可以保证定时任务按照其触发时间的顺序被依次执行。
  6. 求解中位数:利用最大堆和最小堆,可以在O(logn)的时间内查询一组数据的中位数。具体做法是将数据分为两部分,一部分放入最大堆,另一部分放入最小堆,并保持最大堆中的元素个数不大于最小堆中的元素个数加1。这样,最大堆的堆顶元素(最大值)和最小堆的堆顶元素(最小值)的平均值就是当前数据的中位数。当插入新元素时,根据新元素与当前中位数的大小关系,将其放入最大堆或最小堆中,并重新调整两个堆的大小关系以保持平衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/690310.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Tiff文件解析和PackBits解压缩

实现了Tiff图片文件格式的解析&#xff0c;对Tiff文件中的PackBits压缩格式进行解压缩&#xff0c;对Tiff文件中每一个Frame转换成BufferedImage显示。 Java语言实现&#xff0c;Eclipse下开发&#xff0c;AWT显示图片。 public static TIFF Parse(final byte[] bytes) throw…

es6语法总结

【1】语法 &#xff08;1&#xff09;声明变量(let-var-const) 变量提升&#xff1a; 是JavaScript引擎在代码执行前将变量的声明部分提升到作用域顶部的行为。尽管变量的声明被提升了&#xff0c;变量的赋值&#xff08;即初始化&#xff09;仍然保留在原来的位置。因此&…

原型模式类图与代码

现要求实现一个能够自动生成求职简历的程序&#xff0c;简历的基本内容包括求职者的姓名、性别、年龄及工作经历。希望每份简历中的工作经历有所不同&#xff0c;并尽量减少程序中的重复代码。 采用原型模式(Prototype)来实现上述要求&#xff0c;得到如图 7.25 所示的类图。 原…

达梦数据库连接失败:Connect Failure! “Encryption module failed to load“

初次安装达梦数据库&#xff1a;V7 QT5.12.12版本开发调用数据库&#xff0c;最基础的原型调用&#xff1a; { //执行查询语句或则执行sql语句 QSqlDatabase qDb; QSqlDatabase db QSqlDatabase::addDatabase("QDM"); db.setHostName("192.168.2…

PX4 路径规划 航点规划 轨迹跟踪 Matlab/Simulink

一、无人机轨迹算法和仿真 matlab下载和安装 PX4实战之旅_超维空间科技的博客-CSDN博客 查了很多资料。无人机二次开发设计的目标是实现喷涂路径程序设计。决定使用simulink在ubuntu系统上结合jmavsim进行算法设计和仿真。 1.如果安装在ubuntu系统上面&#xff0c;MATLAB占…

基于单片机的直流电机检测与控制系统

摘要&#xff1a; 文章设计一款流电机控制系统&#xff0c;以 STC89C51 作为直流电机控制系统的主控制器&#xff0c;采用 LM293 做为驱动器实现 对直流电机的驱动&#xff0c;采用霍尔实现对直流电机速度的检测&#xff1b;本文对直流电机控制系统功能分析&#xff0c;选择确…

工业中常见大数据技术组件

随着大数据技术在各行各业的广泛应用&#xff0c;数据产品经理的角色也变得越来越重要。了解常见的大数据技术组件对于数据产品经理来说至关重要&#xff0c;因为这有助于他们更好地设计产品架构和功能模块&#xff0c;满足数据处理和分析的需求。在处理海量数据的产品中&#…

计算机视觉——OpenCV实现Lucas-Kanade 光流追踪

1.光流 光流法是计算机视觉中用于估计图像序列中物体运动的关键技术。它类似于观察夜空中的彗星&#xff0c;通过其在天空中的运动轨迹来追踪它的路径。在图像处理中&#xff0c;光流帮助我们理解像素点如何在连续的帧之间移动。 1.1 稀疏光流法 稀疏光流法关注于图像中的关…

OpenCV 入门(二)—— 车牌定位

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

HCIP综合实验

1.拓扑 2.需求分析 1、R4为ISP&#xff0c;其上只能配置IP地址&#xff1b;R4与其他所有直连设备间均使用公有IP。 2、R3、R5、R6、R7为MGRE环境&#xff0c;R3为中心站点。 3、整个OSPF环境IP地址基于172.16.0.0/16划分。 4、减少LSA的更新量&#xff0c;加快收敛&#xf…

antd vue pro (vue 2.x) 多页签详细操作

antd vue pro 多页签配置操作&#xff0c;具体操作如下。 1.引入 tagviews文件 在 store/modules 中创建 tagviews.js &#xff0c;复制一下代码到文件中保存 const state {visitedViews: [],cachedViews: [] }const mutations {ADD_VISITED_VIEW: (state, view) > {if …

ctfshow web入门 php反序列化 web267--web270

web267 查看源代码发现这三个页面 然后发现登录页面直接admin/admin登录成功 然后看到了 ///backdoor/shell unserialize(base64_decode($_GET[code]))EXP <?php namespace yii\rest{class IndexAction{public $checkAccess;public $id;public function __construct(){…