当前位置: 首页 > news >正文

初识数据结构——优先级队列(堆!堆!堆!)

在这里插入图片描述
在这里插入图片描述
⬅(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.lryc.cn/news/618615.html

相关文章:

  • 模板打印技术——Office XLS 打印模板:为政务土地确权定制的纸张替换利器—仙盟创梦IDE
  • LE AUDIO---Volume Control Service
  • Kimi K2 架构深度解析:万亿MoE模型的效率革命与智能体突破
  • 用STM32单片机控制支持正反转的电调
  • 1、JVM内存模型剖析及优化
  • Altium Designer 22使用笔记(6)---板框导入、自绘板框、原点设置
  • 荣耀手机无法连接win11电脑,错误消息:“无法在此设备上加载驱动程序 (hn_usbccgpfilter.sys)。”解决方案
  • 【Linux】Ext系列文件系统
  • 数据结构:后缀表达式:结合性 (Associativity) 与一元运算符 (Unary Operators)
  • 现代化水库运行管理矩阵建设的要点
  • AI Agent——基于 LangGraph 的多智能体任务路由与执行系统实战
  • 【实时Linux实战系列】实时能耗监测与优化技术
  • 《吃透 C++ 类和对象(上):封装、实例化与 this 指针详解》
  • Python训练营打卡Day30-文件的规范拆分和写法
  • 543.二叉树的直径
  • 【前端:Html】--2.进阶:表单
  • 数字孪生重构园区管理效率:技术落地与产业升级的三重跃迁
  • JVM学习笔记-----图解方法执行流程
  • Nginx 启用 HTTPS:阿里云免费 SSL 证书详细图文教程(新手0.5小时可完成)
  • openssl中,公钥和私钥的区别和作用?
  • API 接口接入开发全演示:淘宝商品数据实时抓取
  • 代码随想录刷题Day29
  • 基于51单片机220V交流电流检测系统过流阈值报警设计
  • 通信接口与通信约规
  • 【牛客刷题】REAL806 放它一马:怪物经验值最大化策略详解
  • 【基于DesignStart的M3 SoC】
  • 终端安全检测和防御技术
  • UGUI源码剖析(6):遮罩的“魔法”与“算法”——从C#到Shader,彻底揭示Mask与RectMask2D的原理
  • OpenHarmony编译与烧录
  • HTTPS服务