在这里插入图片描述
在这里插入图片描述
⬅(click)


今天就让我们来聊聊这个让无数程序员又爱又恨的数据结构——堆(Heap)。

一、优先级队列 vs 普通队列

特性普通队列优先级队列
出队顺序FIFO(先进先出)按优先级高低(默认小的先出)
底层实现数组/链表通常用堆实现
时间复杂度O(1)插入O(logN),删除O(logN)
Java实现Queue接口PriorityQueue类
典型应用场景消息队列、BFS算法任务调度、TopK问题
队列
普通队列
优先级队列
FIFO
基于优先级
实现方式
有序数组
无序数组

二、堆:一棵"偏心的"完全二叉树

堆的类型对比

类型特点应用场景
大根堆父节点 ≥ 子节点堆排序(升序)、TopK最小
小根堆父节点 ≤ 子节点堆排序(降序)、TopK最大
二叉堆完全二叉树实现,常用数组存储最常用实现
斐波那契堆更优的理论时间复杂度,但实现复杂图算法优化
// 堆的数组表示
parent(i) = (i-1)/2  // 找父节点
left(i) = 2*i + 1    // 左孩子
right(i) = 2*i + 2    // 右孩子
完全二叉树
数组存储
大根堆
小根堆
空间利用率高
索引计算快

三、堆的核心操作:上下调整

操作复杂度对比

操作时间复杂度空间复杂度说明
插入(offer)O(logN)O(1)需要向上调整(shiftUp)
删除(poll)O(logN)O(1)需要向下调整(shiftDown)
查看(peek)O(1)O(1)直接返回堆顶元素
建堆O(N)O(1)自底向上调整比逐个插入更高效
// 向下调整示例(小根堆)
void shiftDown(int[] arr, int parent, int len) {int child = 2*parent + 1;while (child < len) {// 找出较小的孩子if (child+1 < len && arr[child+1] < arr[child]) child++;// 如果父节点已经比孩子小,调整结束if (arr[parent] <= arr[child]) break;swap(arr, parent, child);  // 交换父子parent = child;            // 继续向下调整child = 2*parent + 1;}
}

四、堆排序 vs 快速排序

特性堆排序快速排序
时间复杂度O(NlogN)O(NlogN)平均
空间复杂度O(1)O(logN)递归栈
稳定性不稳定不稳定
最坏情况O(NlogN)O(N²)
数据访问模式跳跃访问(缓存不友好)顺序访问(缓存友好)
适用场景大数据量中小数据量
排序算法
比较排序
堆排序
快速排序
原地排序
不稳定
分治思想
平均更快

五、PriorityQueue使用指南

构造方法对比

构造方法说明
new PriorityQueue<>()默认容量11,自然排序
new PriorityQueue<>(int capacity)指定初始容量
new PriorityQueue<>(Comparator)自定义比较器(可实现大根堆)
new PriorityQueue<>(Collection)用已有集合初始化(自动建堆)
// 大根堆实现
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a,b) -> b-a);// 自定义对象排序
PriorityQueue<Student> pq = new PriorityQueue<>((s1, s2) -> s1.score != s2.score ? s2.score - s1.score :  // 分数高的在前s1.name.compareTo(s2.name)  // 分数相同按名字
);

六、TopK问题的三种解法对比

方法时间复杂度空间复杂度适用场景
快速排序+取前KO(NlogN)O(logN)数据可全部装入内存
堆排序O(NlogK)O(K)海量数据,K较小
冒泡K次O(N*K)O(1)K非常小(如K=1,2)
TopK问题
排序法
堆方法
分治法
全排序后取前K
维护大小为K的堆
类似快速选择
小根堆求最大K
大根堆求最小K

七、堆的常见面试题

1. 堆的建立过程(以小根堆为例)

//向下调整方法(复杂度logN)public static void shiftDown(int[] array, int index){//要调整的父节点int parent = index;//要调整的孩子节点int child = 2*parent + 1;while (child < array.length){//child+1其实代表的是右子树//判断左右子树大小if(child+1<array.length && array[child+1] < array[child]){//左右子树对调child = child+1;}//判断左子树和父节点的大小if (array[child] >= array[parent]){break;}else{int temp = array[parent];array[parent] = array[child];array[child] = temp;//更新父节点和子节点的指向parent = child;child = 2*parent +1;}}}/***建堆操作复杂度O(n)* @param array*/public static void createHeap(int[] array){//要先找到最后一个非叶子节点int lastLeaf  = array.length-1;int lastParent = (lastLeaf-1)/2;for (int i = lastParent; i >= 0; i--){shiftDown(array, i);}}

2. 堆的应用场景总结

应用场景使用的堆类型原因说明
堆排序大根堆/小根堆升序用大根堆,降序用小根堆
TopK最大元素小根堆维护K个元素的小根堆,淘汰小的
TopK最小元素大根堆维护K个元素的大根堆,淘汰大的
任务调度(优先级高的先执行)大根堆优先级高的在堆顶
合并K个有序链表小根堆每次取最小节点,效率O(logK)
Dijkstra算法小根堆每次取距离最小的节点

八、总结:堆的"堆"德

堆的优缺点分析

优点:

  1. 插入/删除时间复杂度稳定在O(logN)
  2. 获取极值(堆顶)只需O(1)
  3. 可以高效解决TopK问题
  4. 堆排序是原地排序,空间复杂度O(1)

缺点:

  1. 访问非堆顶元素效率低(需要遍历)
  2. 不是稳定排序(相同元素可能换位)
  3. 缓存不友好(数组跳跃访问)
堆的优点
高效插入删除
快速获取极值
解决TopK
原地排序
堆的缺点
非随机访问
不稳定
缓存不友好

九、终极对比表:堆 vs 其他数据结构

特性二叉搜索树跳表哈希表
查找极值O(1)O(logN)O(logN)O(N)
插入/删除O(logN)O(logN)O(logN)O(1)平均
有序性部分有序(仅堆顶)完全有序完全有序无序
空间复杂度O(N)O(N)O(N)O(N)
实现难度中等中等困难中等
典型应用优先级队列、TopK范围查询、有序数据高性能有序数据结构快速查找、去重

最后的小幽默

程序员的世界里:

  • 当你学会堆:哇!我"堆"数据结构理解好深!
  • 当你写堆代码:这bug怎么"堆"了这么多!
  • 当你面试被问堆:面试官,咱们能"堆"心一点吗?

在这里插入图片描述

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

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

相关文章

嵌入式学习day25

fwrite&#xff1a;fread&#xff1a;fread/fwrite&#xff1a;拷贝图片&#xff1a;#include <stdio.h>int main(void) {FILE *fsrc NULL;FILE *fdst NULL;char tmpbuff[4096] {0};size_t nret 0;fsrc fopen("src.jpg", "r");if (NULL fsrc){…

2025年中科院2区红杉优化算法Sequoia Optimization Algorithm-附Matlab免费代码

1. 简介 提出了红杉优化算法&#xff08;SequoiaOA&#xff09;&#xff0c;这是一种受红杉森林生态系统自我调节动力学和弹性启发的新型元启发式方法&#xff0c;不同于传统的奇异生物学或现象学灵感。开发一个全面的生态系统驱动框架&#xff0c;包括数学建模、系统分析和通过…

【C#】从 Queue 到 ConcurrentQueue:一次对象池改造的实战心得

背景 最近在做一个图像处理的 WPF 项目&#xff0c;底层使用 Halcon 的 HObject 来存放图像。为了减少频繁创建和释放对象带来的开销&#xff0c;我实现了一个对象池&#xff0c;用来存放 HObject&#xff0c;方便后续流程复用。 最初的实现用的是 .NET 自带的 Queue<T>&…

深度解析 AS32S601 芯片 CAN Bus Off 机制:从原理到应用的全流程指南

一、前言在汽车电子、工业自动化等众多领域&#xff0c;CAN 总线作为一种可靠的通信协议被广泛应用。而 AS32S601 芯片凭借其卓越的性能和可靠性&#xff0c;在这些领域也发挥着重要作用。其中&#xff0c;CAN Bus Off 功能作为 CAN 总线通信中的关键错误处理机制&#xff0c;对…

PyCharm Community 2024.2.3.exe 安装教程(详细步骤,附安装包下载)

​1. 下载安装包​ 安装下载地址&#xff1a;https://pan.quark.cn/s/ca11cb817ee5&#xff0c;你已经下载好了 pycharm-community-2024.2.3.exe 这个文件&#xff08;通常是从 JetBrains 官网下的&#xff09;。双击这个 .exe 文件开始安装。 ​2. 开始安装向导​ 双击后&am…

JAVA:SpringBoot 集成 Selenium 实现高效爬虫

🌐 1、简述 在互联网数据采集中,传统基于 Jsoup 或 HttpClient 的爬虫方案面对复杂 JavaScript 渲染页面时经常力不从心。此时,Selenium WebDriver 提供了更强大的模拟真实浏览器行为能力,成为爬取动态网站的利器。 为了绕过反爬机制,结合 IP 代理池 是提升稳定性和并发…

终端安全检测和防御技术

目录 1. 终端安全风险 2. 终端安全检测和防御技术 3. 网关杀毒技术 3.1 计算机病毒工作步骤 3.2 杀毒防御产品 3.3 网关杀毒功能优势 3.4 网关杀毒实现方式 4.僵尸网络检测和防御技术 4.1 僵尸网络 4.2 僵尸网络的形成过程&#xff08;APT场景下&#xff09; 4.3 检测…

Java缓冲流

字节缓冲流&#xff1a;原理&#xff1a;底层自带长度为8192的缓冲区提高性能拷贝文件一次读一个字节一次读一个字节数组字节缓冲流的读写原理字符缓冲流&#xff1a;特定方法字符缓冲输入流基本写法输入所有数据字符缓冲流输出总结

web服务器tomcat内部工作原理以及样例代码

目录 一、Tomcat 运行原理与 Servlet 机制 1、为什么 Java Web 项目需要 Tomcat 2. 进程模式 vs 线程模式 3、Servlet / Controller 是怎么跟 Tomcat 对接的? 4、java反射与代理机制 ※--高级知识点 (1)原理 (1)样例:用反射和注解模拟 Tomcat 处理 HTTP 请求时,动…

AI赋能IT服务管理:从被动响应到智能驱动的跃迁

过去十年&#xff0c;IT服务管理&#xff08;ITSM&#xff09;经历了从纸质工单到数字化平台的变革&#xff0c;但无论工具多么先进&#xff0c;大多数IT团队依然面临着相同的困境&#xff1a;事件处理速度跟不上业务变化人工重复操作占用大量时间数据虽多&#xff0c;却缺乏可…

云计算-K8s 核心组件之CronJob、RBAC、HPA ,LimitRange、DaemonSet、nodeSelector如何作战?

目录 1.CronJob管理 2.RBAC管理 3.HPA管理 4.健康检查 5.LimitRange管理 6.DaemonSet管理 7.nodeSelector管理 简介 1. CronJob&#xff08;定时任务控制器&#xff09; 按固定时间间隔&#xff08;类似 Linux cron&#xff09;自动触发一次性任务&#xff08;Job&#…

数据分析学习总结之实例练习(双十一淘宝美妆)

本次通过对双十一淘宝美妆数据的分析实践&#xff0c;我系统掌握了数据处理与分析的完整流程&#xff0c;从数据初步认知到深度挖掘&#xff0c;再到可视化呈现与结论提炼&#xff0c;收获颇丰。以下是具体的学习总结&#xff1a;一、数据初步了解&#xff1a;奠定分析基础在分…

如何评估一个需求的业务价值

要科学、全面地评估一个需求的业务价值&#xff0c;核心在于建立一个多维度的、从战略到财务、从客户到风险的“价值罗盘”&#xff0c;并运用这套罗盘&#xff0c;对需求进行系统性的、数据驱动的量化与定性分析。一套成熟的价值评估体系&#xff0c;其构建必须涵盖五大关键视…

day38_2025-08-12

一、 图像数据的介绍 1.1 灰度图像 从这里开始我们进入到了图像数据相关的部分&#xff0c;也是默认你有之前复试班计算机视觉相关的知识&#xff0c;但是一些基础的概念我仍然会提。 昨天我们介绍了minist这个经典的手写数据集&#xff0c;作为图像数据&#xff0c;相较于结构…

Kubernetes1.28-单Master集群部署

一、 服务器环境及初始化 1、架构分析 集群角色主机名操作系统IP地址masterk8s-masterOpenEuler24.03192.168.166.128nodek8s-node1OpenEuler24.03192.168.166.129nodek8s-node2OpenEuler24.03192.168.166.130 2、初始化 所有节点都需要初始化&#xff01; 2.1、清空Iptal…

使用pyqt5实现可勾选的测试用例界面

目录 界面 代码 python有哪些自动化测试的库和html的报告的库可以和这个软件结合使用的 **一、自动化测试核心库** **二、HTML报告生成库** **三、其他实用工具** **与您的工具结合建议** 参考 界面 代码 import sys import time import random from PyQt5.QtWidgets import (…

C语言变量的声明和定义有什么区别?

定义&#xff1a;定义&#xff1a;为变量分配地址和存储空间声明&#xff1a;不分配地址和存储空间一个变量可以在多个地方声明&#xff0c;但是只在一个地方定义。加入extern修饰的是变量的声明&#xff0c;说明此变量将在文件或在文件后面部分定义。1.变量声明作用&#xff1…

imx6ull-驱动开发篇20——linux互斥体实验

目录 实验程序编写 修改设备树文件 LED 驱动修改 mutex.c 测试mutexApp.c Makefile 文件 运行测试 在之前的文章里&#xff0c;我们学习了&#xff1a;驱动开发篇16——信号量与互斥体。 本讲实验里&#xff0c;我们来使用互斥体mutex实现 LED 灯互斥访问的功能&#x…

[4.2-2] NCCL新版本的register如何实现的?

文章目录1->2->31. ncclRegisterP2pIpcBuffer2. ncclIpcLocalRegisterBuffer(..., 1, 0,...)3. ipcRegisterBuffer(..., regRecord,..., isLegacyIpc)4. p2pProxyRegister()1->2->3 1. ncclRegisterP2pIpcBuffer 在enqueue.cc内的调用是&#xff1a; NCCLCHECK(…

在idea中git切换分支,但是我的文件没add,没commit

这是一个很悲伤的故事&#xff0c;我朋友一个下午写了4个小时的代码&#xff0c;差不多10多个类&#xff0c;都在切换分支的时候。IDEA发现有冲突&#xff0c;然后就要resolve conflict&#xff0c;发现自己不知道怎么操作&#xff0c;就点了abort & rollback。然后所有代码…