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

【UCB CS 61B SP24】Lecture 21: Data Structures 5: Priority Queues and Heaps 学习笔记

本文介绍了优先队列与堆,分析了最小堆的插入与删除过程,并用 Java 实现了一个通用类型的最小堆。

1. 优先队列

1.1 介绍

优先队列是一种抽象数据类型,其元素按照优先级顺序被处理。不同于普通队列的先进先出(FIFO),优先队列每次取出优先级最高(或最低)的元素。

在 Java 中,PriorityQueue 是基于(Heap)实现的,默认使用自然排序(最小堆),也可以通过自定义 Comparator 调整优先级顺序:

package CS61B.Lecture21;import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;public class PriorityQueueDemo {public static void main(String[] args) {PriorityQueue<Integer> Q = new PriorityQueue<>();  // 默认为小根堆PriorityQueue<Integer> RQ = new PriorityQueue<>(Collections.reverseOrder());  // 大根堆for (int i = 5; i > 0; i--)Q.add(i);  // 也可以用 offer() 方法System.out.println(Q);  // [1, 2, 4, 5, 3],直接输出不一定有序while (!Q.isEmpty())System.out.print(Q.poll() + " ");  // 也可以用 remove() 方法,输出 1 2 3 4 5System.out.println();RQ.addAll(List.of(8, 6, 7, 10, 9));while (RQ.peek() != null)System.out.print(RQ.remove() + " ");  // 10 9 8 7 6System.out.println();}
}

堆是一种完全二叉树,完全二叉树是指除了最后一层外,其他层的节点都必须是满的(所有可能的节点都存在),且最后一层的节点必须尽可能靠左排列。最后一层可以不满,但所有节点必须集中在左侧,中间不能有空缺。完全二叉树的高度为 ⌊ l o g n ⌋ + 1 \lfloor log n\rfloor + 1 logn+1,在相同节点数的二叉树中高度最小。

堆又分为最小堆和最大堆:

  • 最小堆:父节点的值 ≤ 子节点的值,堆顶元素为最小值;
  • 最大堆:父节点的值 ≥ 子节点的值,堆顶元素为最大值。

堆通常用数组实现,利用完全二叉树的性质能够简化父子节点索引计算,优先级最高的元素一定在堆顶,也就是索引为 0 的节点:

  • 父节点索引:(i - 1) / 2
  • 左子节点索引:2 * i + 1
  • 右子节点索引:2 * i + 2

下图是一个最小堆的示例:

在这里插入图片描述

1.2 插入

我们以最小堆为例,插入步骤如下:

  • 将新元素插入到堆的末尾(数组的最后一个位置)。
  • 上浮(Swin)调整:从新元素的位置开始,与其父节点比较。
    • 如果新元素的值小于父节点,则交换两者的位置。
    • 重复此过程,直到新元素到达根节点,或满足父节点 ≤ 当前节点的条件。

我们用图片来展示一下最小堆的插入与上浮过程,首先在末尾插入节点 3,然后判断与其父节点的大小关系,小于父节点 5,因此与父节点交换位置,然后继续判断还是小于其父节点 5,和父节点交换,最后判断该节点大于等于其父节点 1,完成上浮调整:

在这里插入图片描述

1.3 删除

还是以最小堆为例,删除步骤如下:

  • 移除堆顶元素(最小值),将其返回。
  • 将堆的最后一个元素移动到堆顶(填补空缺,同时保持完全二叉树的状态)。
  • 下沉(Sink)调整:从堆顶开始,与左右子节点中的较小者比较。
    • 如果当前节点的值大于较小子节点,则交换两者的位置。
    • 重复此过程,直到当前节点到达叶子节点,或满足父节点 ≤ 任意子节点的条件。

同样用图片展示一下最小堆的删除与下沉过程,我们在前面的最小堆上删除堆顶元素(最小值),删除后先将最后一个元素 5 移动到堆顶,然后进行下沉调整,判断 5 大于较小子节点 1,因此与 1 进行交换,接着继续判断还是小于较小子节点 3,因此与 3 进行交换,交换后已经为叶子节点,完成下沉调整:

在这里插入图片描述

可以看到堆的上浮与下沉操作最坏情况下就是遍历树的高度,因此添加和删除操作的时间复杂度最坏情况下均为 O ( l o g n ) O(log n) O(logn)。优先队列与其他数据结构的时间复杂度对比如下:

数据结构插入查看最值删除最值空间复杂度适用场景
有序数组 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1) O ( n ) O(n) O(n) O ( n ) O(n) O(n)静态数据、极少插入
平衡搜索树 O ( l o g n ) O(log n) O(logn) O ( l o g n ) O(log n) O(logn) O ( l o g n ) O(log n) O(logn) O ( n ) O(n) O(n)需范围查询或全局有序
哈希表 O ( 1 ) O(1) O(1) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n)快速查找某个键、无顺序要求
二叉堆 O ( l o g n ) O(log n) O(logn) O ( 1 ) O(1) O(1) O ( l o g n ) O(log n) O(logn) O ( n ) O(n) O(n)动态数据、频繁插入和提取

2. Java 实现最小堆

相信看完上面的讲解也能感觉到堆的实现并不复杂,Java 实现最小堆代码如下:

package CS61B.Lecture21;public class MinHeap<T extends Comparable<T>> {private T[] heap;private int size;private static final int DEFAULT_CAPACITY = 2;  // 默认容量public MinHeap() {this(DEFAULT_CAPACITY);}public MinHeap(int capacity) {heap = (T[]) new Comparable[capacity];size = 0;}/** 核心操作:添加 */public void add(T x) {if (size >= heap.length) resize();heap[size] = x;swim(size);  // 从末尾开始上浮size++;}/** 核心操作:删除并返回堆顶元素(最小值) */public T remove() {if (size == 0) return null;T root = heap[0];heap[0] = heap[--size];heap[size] = null;  // 清除引用,防止内存泄漏sink(0);  // 从根节点开始下沉return root;}/** 核心操作:返回堆顶元素(最小值) */public T peek() {return heap[0];}/** 获取大小 */public int size() {return size;}/** 是否为空 */public boolean isEmpty() {return size == 0;}/** 核心操作:上浮 */private void swim(int idx) {int parent = idx - 1 >> 1;while (parent >= 0 && heap[idx].compareTo(heap[parent]) < 0) {swap(idx, parent);idx = parent;parent = idx - 1 >> 1;}}/** 核心操作:下沉 */private void sink(int idx) {int left = (idx << 1) + 1;  // 左子节点的索引while (left < size) {  // 当存在子节点即当前节点还不是叶子节点时循环int right = left + 1;int minChild = left;  // 先假设最小的子节点为左子节点if (right < size && heap[right].compareTo(heap[left]) < 0) minChild = right;if (heap[idx].compareTo(heap[minChild]) <= 0) break;  // 如果已经小于等于最小子节点则完成下沉swap(idx, minChild);idx = minChild;left = (idx << 1) + 1;}}/** 将容量扩容至原来的两倍 */private void resize() {int newCapacity = heap.length * 2;T[] newHeap = (T[]) new Comparable[newCapacity];System.arraycopy(heap, 0, newHeap, 0, size);heap = newHeap;}/** 交换 heap 中两个位置的元素 */private void swap(int idx1, int idx2) {T temp = heap[idx1];heap[idx1] = heap[idx2];heap[idx2] = temp;}/** 测试 */public static void main(String[] args) {MinHeap<Integer> minHeap = new MinHeap<>();for (int i = 5; i > 0; i--) minHeap.add(i);  // 按 5 4 3 2 1 的顺序插入while (!minHeap.isEmpty())System.out.print(minHeap.remove() + " ");  // 1 2 3 4 5System.out.println();}
}

相关文章:

【UCB CS 61B SP24】Lecture 21: Data Structures 5: Priority Queues and Heaps 学习笔记

本文介绍了优先队列与堆&#xff0c;分析了最小堆的插入与删除过程&#xff0c;并用 Java 实现了一个通用类型的最小堆。 1. 优先队列 1.1 介绍 优先队列是一种抽象数据类型&#xff0c;其元素按照优先级顺序被处理。不同于普通队列的先进先出&#xff08;FIFO&#xff09;&…...

mapbox高阶,结合threejs(threebox)添加三维球体

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️threebox Sphere静态对象二、🍀使用t…...

QEMU源码全解析 —— 块设备虚拟化(1)

本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 详解全虚拟半虚拟及硬件辅助虚拟化技术-百度开发者中心 特此致谢! 序言 本专栏之前的系列文章,讲了很多QEMU/KVM相关知识,其中一部分内容是设备的虚拟…...

IDEA中Git版本回退终极指南:Reset与Revert双方案详解

目录 前言一、版本回退前置知识二、Reset方案&#xff1a;整体改写历史1、IDEA图形化操作&#xff08;推荐&#xff09;1.1、查看提交历史1.2、选择目标版本1.3、选择回退模式1.3.1、Soft&#xff08;推荐&#xff09;1.3.2、Mixed1.3.3、Hard&#xff08;慎用&#xff09;1.3.…...

Flutter 学习之旅 之 flutter 使用 flutter_screenutil 简单进行屏幕适配

Flutter 学习之旅 之 flutter 使用 flutter_screenutil 简单进行屏幕适配 目录 Flutter 学习之旅 之 flutter 使用 flutter_screenutil 简单进行屏幕适配 一、简单介绍 二、简单介绍 flutter_screenutil 三、安装 carousel_slider 四、简单案例实现 五、关键代码 六、补…...

实验一:在Windows 10/11下配置和管理TCP/IP

目录 1.【实训目标】 2.【实训环境】 3.【实训内容】 4.【实训步骤】 1.【实训目标】 1.了解网络基本配置中包含的协议、服务、客户端。 2.了解Windows支持的网络协议及参数设置方法。 3.掌握TCP/IP协议的配置。 2.【实训环境】 硬件环境&#xff1a;每人一台计算机&a…...

基于hive的电信离线用户的行为分析系统

标题:基于hive的电信离线用户的行为分析系统 内容:1.摘要 随着电信行业的快速发展&#xff0c;用户行为数据呈现出海量、复杂的特点。为了深入了解用户行为模式&#xff0c;提升电信服务质量和精准营销能力&#xff0c;本研究旨在构建基于 Hive 的电信离线用户行为分析系统。通…...

Rust WebAssembly 入门教程

一、开发环境搭建 1. 基础工具安装 # 安装 Rust curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh# 安装 wasm-pack cargo install wasm-pack# 安装开发服务器 cargo install basic-http-server# 安装文件监听工具 cargo install cargo-watch2. VSCode 插件安装…...

部署RabbitMQ集群详细教程

部署RabbitMQ集群详细教程 下面是一份在 Ubuntu 环境下部署 RabbitMQ 集群的详细步骤说明&#xff0c;涉及主机名设置、Erlang & RabbitMQ 安装、管理插件启用、集群通信 Cookie 配置、节点加入集群、镜像队列策略设置以及集群验证等。为了演示方便&#xff0c;以下示例假…...

20250306JIRA添加企业微信邮箱通知

文章目录 一&#xff0c;参考链接如下二&#xff0c;补充内容1&#xff0c;登录企业邮箱2&#xff0c;设置密码3&#xff0c;设置收发信设置 一&#xff0c;参考链接如下 参考链接&#xff1a;https://blog.csdn.net/icett/article/details/142520823 二&#xff0c;补充内容…...

代码随想录算法训练营第五十七天 | 101. 孤岛的总面积 102. 沉没孤岛 103. 水流问题 104.建造最大岛屿

101. 孤岛的总面积 题目链接&#xff1a;KamaCoder 文档讲解&#xff1a;代码随想录 状态&#xff1a;AC Java代码&#xff1a; import java.util.*;class Main {static int count 0;static int res 0;static boolean island true;public static int[][] dir new int[][]{…...

llamafactory大模型微调教程(周易大模型案例)

1.环境说明 操作系统&#xff1a;ubuntu 20 基础模型&#xff1a;Qwen2.5-1.5B-Instruct 工具&#xff1a;llamafactory GPU&#xff1a;四张4090 2、环境部署 2.1 下载基础模型 # 1、下载 modelscope pip install modelscope#2、模型下载 cd /data/ cat >> download…...

excel 斜向拆分单元格

右键-合并单元格 右键-设置单元格格式-边框 在设置好分割线后&#xff0c;你可以开始输入文字。 需要注意的是&#xff0c;文字并不会自动分成上下两行。 为了达到你期望的效果&#xff0c;你可以通过 同过左对齐、上对齐 空格键或使用【AltEnter】组合键来调整单元格中内容的…...

【JAVA架构师成长之路】【JVM实战】第2集:生产环境内存飙高排查实战

课程标题:生产环境内存飙高排查实战——从堆转储到代码修复的15分钟指南 目标:掌握内存泄漏与OOM问题的系统性排查方法,快速定位代码或配置缺陷 0-1分钟:问题引入与核心现象 线上服务内存持续增长,触发频繁Full GC甚至OOM(OutOfMemoryError),导致服务崩溃。常见诱因:…...

MATLAB实现遗传算法优化风电_光伏_光热_储热优化

1. 问题定义 目标&#xff1a;最小化输出负荷与需求负荷的偏差平方和。决策变量&#xff1a;每个时间步长的风电、光伏、光热和储热输出功率。约束条件&#xff1a; 风电、光伏、光热的输出功率不得超过其最大容量。储热系统的输出功率&#xff08;充放电&#xff09;不得超过…...

JCRQ1河马算法+四模型对比!HO-CNN-GRU-Attention系列四模型多变量时序预测

JCRQ1河马算法四模型对比&#xff01;HO-CNN-GRU-Attention系列四模型多变量时序预测 目录 JCRQ1河马算法四模型对比&#xff01;HO-CNN-GRU-Attention系列四模型多变量时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于HO-CNN-GRU-Attention、CNN-GRU-Attent…...

react中的fiber和初次渲染

源码中定义了不同类型节点的枚举值 组件类型 文本节点HTML标签节点函数组件类组件等等 src/react/packages/react-reconciler/src/ReactWorkTags.js export const FunctionComponent 0; export const ClassComponent 1; export const IndeterminateComponent 2; // Befo…...

LLM 大模型基础认知篇

目录 1、基本概述 2、大模型工作原理 3、关键知识点 &#xff08;1&#xff09;RAG 知识库 &#xff08;2&#xff09;蒸馏 &#xff08;3&#xff09;微调 &#xff08;4&#xff09;智能体 1、基本概述 大型语言模型&#xff08;Large Language Model, LLM&#xff09…...

leetcode700-二叉搜索树中的搜索

leetcode 700 思路 我们需要先了解一下二叉搜索树的特性&#xff1a; 左子树的所有节点值 < 当前节点的值。右子树的所有节点值 > 当前节点的值。这个特性适用于树中的每个节点 那么根据这个特性&#xff0c;我们可以通过根节点的值和目标值的大小来判断后序的走向&…...

《MySQL三大核心日志解析:Undo Log/Redo Log/Bin Log对比与实践指南》

MySQL三大核心日志解析&#xff1a;Undo Log/Redo Log/Bin Log对比与实践指南 一、核心日志全景概览 在MySQL数据库体系中&#xff0c;Undo Log、Redo Log和Bin Log构成了事务处理和数据安全的三大基石。这三大日志各司其职&#xff0c;协同保障了数据库的ACID特性与高可用架…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...