C#进阶学习(十七)PriorityQueue<TElement, TPriority>优先级队列的介绍

1. PriorityQueue是什么?作用是什么?

        定义PriorityQueue<TElement, TPriority> 是 C# (.NET 6+ 引入) 中的泛型优先级队列数据结构。

        那么是什么是优先级队列呢?优先级队列是一种抽象数据结构,其核心特性是元素按照优先级顺序进行管理,而非传统队列的先进先出(FIFO)规则。在优先级队列中,每次被取出处理的元素是当前队列中优先级最高的(或最低的,取决于具体实现),而非最早进入队列的元素。这种特性使其在需要动态调整处理顺序的场景中具有独特优势。

        作用:按优先级管理元素,优先级高(值小)的元素先出队。常用于需要按特定顺序处理任务的场景,如:

任务调度(高优先级任务优先执行)。

算法实现(如 Dijkstra 最短路径算法、Huffman 编码)。

事件驱动系统(按时间戳处理事件)。

2. 底层实现与复杂度

        底层结构:基于 二叉堆(最小堆) 实现,确保堆顶元素始终是优先级最高的(即优先级值最小)。

  • 时间复杂度

    入队 (Enqueue):O(log n)

    出队 (Dequeue):O(log n)

    查看堆顶 (Peek):O(1)

  • 空间复杂度O(n)(动态数组存储堆节点)。

3.优先级的次序

        在 C# 的 PriorityQueue<TElement, TPriority> 中,优先级规则完全由 TPriority 类型的比较逻辑决定。默认的次序如下:

(1) 数值类型(如 intdouble 等)

        默认规则:优先级值 越小 的优先级越高(即最小堆)。

        示例

var queue = new PriorityQueue<string, int>();
queue.Enqueue("Task 1", 3);
queue.Enqueue("Task 2", 1); // 优先级更高
queue.Enqueue("Task 3", 2);
// 出队顺序:Task 2 → Task 3 → Task 1

(2) 字符串类型(string 

        默认规则:按 字典序(区分大小写)升序排序。

                比较规则:"A" < "B" < "a" < "b"(基于 Unicode 码点)。

        示例:

var queue = new PriorityQueue<string, string>();
queue.Enqueue("Apple", "Zebra"); // 优先级低
queue.Enqueue("Banana", "Apple"); // 优先级高
// 出队顺序:Banana(Apple) → Apple(Zebra)

        小结,默认里面是按照升序进行组成的,每次默认弹出的是优先级最高的,想自定义出队列规则,需要自定义比较器 。若要覆盖默认规则(如让数值越大优先级越高),需实现 IComparer<TPriority> 接口,并在构造函数中传入比较器。例如:

示例 1:数值降序优先级(最大堆)
using System.Collections.Generic;// 自定义比较器:数值越大优先级越高
public class MaxPriorityComparer : IComparer<int>
{public int Compare(int x, int y) => y.CompareTo(x); // 反转默认顺序
}public class Program
{public static void Main(){// 使用自定义比较器var queue = new PriorityQueue<string, int>(new MaxPriorityComparer());queue.Enqueue("Task 1", 3); // 优先级高(数值大)queue.Enqueue("Task 2", 1); // 优先级低queue.Enqueue("Task 3", 2);// 出队顺序:Task 1 → Task 3 → Task 2}
}
示例 2:字符串按长度排序
public class StringLengthComparer : IComparer<string>
{public int Compare(string x, string y) => x.Length.CompareTo(y.Length);
}public class Program
{public static void Main(){var queue = new PriorityQueue<string, string>(new StringLengthComparer());queue.Enqueue("Apple", "Zebra");    // 长度 5queue.Enqueue("Banana", "Ant");     // 长度 3 → 优先级更高queue.Enqueue("Cherry", "Elephant");// 长度 8// 出队顺序:Banana → Apple → Cherry}
}

小结:

场景规则实现方式
默认优先级(数值升序)值越小优先级越高无需额外代码,直接使用默认队列
数值降序(最大堆)值越大优先级越高自定义 IComparer<int>
字符串按长度排序长度越短优先级越高自定义 IComparer<string>
不区分大小写的字符串排序按字母顺序忽略大小写自定义 IComparer<string>

4. 主要使用方式与代码示例

示例 1:基本使用(默认升序优先级)

using System;
using System.Collections.Generic;var priorityQueue = new PriorityQueue<string, int>();// 入队:元素 + 优先级(优先级值越小,优先级越高)
priorityQueue.Enqueue(element: "Task 1", priority: 3); // 低优先级
priorityQueue.Enqueue("Task 2", 1); // 高优先级
priorityQueue.Enqueue("Task 3", 2);// 出队:按优先级升序(值小的先出)
while (priorityQueue.TryDequeue(out string task, out int priority))
{Console.WriteLine($"处理任务: {task}, 优先级: {priority}");
}
// 输出顺序:
// 处理任务: Task 2, 优先级: 1
// 处理任务: Task 3, 优先级: 2
// 处理任务: Task 1, 优先级: 3
示例 2:自定义降序优先级比较器

关于比较器的知识可以看这里:C#中的比较器

// 自定义比较器:优先级值越大,优先级越高
public class MaxPriorityComparer : IComparer<int>
{public int Compare(int x, int y) => y.CompareTo(x); // 降序
}public class Program
{public static void Main(){// 使用自定义比较器初始化队列var queue = new PriorityQueue<string, int>(new MaxPriorityComparer());queue.Enqueue("Task A", 5);queue.Enqueue("Task B", 10); // 优先级更高(值更大,但比较器反转逻辑)while (queue.TryDequeue(out var task, out var priority)){Console.WriteLine(task); // 输出顺序:Task B → Task A}}
}
示例 3:处理队列为空的情况
var queue = new PriorityQueue<char, int>();
queue.Enqueue('A', 1);// 安全出队(避免异常)
if (queue.TryDequeue(out char element, out int priority))
{Console.WriteLine($"出队元素: {element}");
}if (!queue.TryDequeue(out element, out priority))
{Console.WriteLine("队列为空!");
}

5. 主要 API 和属性汇总

属性
属性名类型说明
Countint队列中当前元素的数量。
方法
方法名参数返回值/行为
Enqueue(TElement element, TPriority priority)element: 元素;priority: 优先级将元素按优先级插入队列。
Dequeue()移除并返回优先级最高的元素。若队列为空,抛出 InvalidOperationException
TryDequeue(out TElement element, out TPriority priority)element: 出队元素;priority: 优先级安全出队,返回是否成功。若队列为空,返回 false
Peek()返回优先级最高的元素但不移除。若队列为空,抛出异常。
TryPeek(out TElement element, out TPriority priority)element: 堆顶元素;priority: 优先级安全查看堆顶元素,返回是否成功。若队列为空,返回 false
Clear()清空队列中的所有元素。
构造函数
构造函数说明
PriorityQueue()使用默认优先级比较器(升序)。
PriorityQueue(IComparer<TPriority>? comparer)指定自定义优先级比较器。
PriorityQueue(IEnumerable<(TElement Element, TPriority Priority)> items)从现有元素集合初始化队列。

        其中两个重要方法的解释:

构造函数 PriorityQueue(IEnumerable<(TElement, TPriority)> items)

        作用:通过一个包含元素及其优先级的元组集合 批量初始化优先级队列,直接构建堆结构,避免多次调用 Enqueue 的开销。说白了,其实就是初始化,你直接塞一个这样的组合进去。

        特点:

批量添加优化:

时间复杂度:O(n)O(n)(直接构建堆,比逐个调用 Enqueue 的 O(nlog⁡n)O(nlogn) 更高效)。空间复杂度:O(n)O(n)(存储所有元素)。

自动堆化(Heapify):
内部会将传入的集合直接转换为堆结构,无需手动调整顺序。

支持自定义比较器:
可结合其他构造函数指定优先级比较规则。就是,你在初始化之后,直接往后面,塞一个比较器,他是支持这个重载的。

示例:

using System;
using System.Collections.Generic;var items = new List<(string Element, int Priority)>
{("Task 1", 3),("Task 2", 1), // 高优先级("Task 3", 2)
};// 使用集合初始化队列
var queue = new PriorityQueue<string, int>(items);// 出队顺序:Task 2 → Task 3 → Task 1
while (queue.TryDequeue(out var task, out var priority))
{Console.WriteLine($"{task} (优先级: {priority})");
}

方法 TryDequeue(out TElement element, out TPriority priority)

        作用:安全地取出并删除优先级最高的元素,避免队列为空时抛出异常。适合不确定队列状态时的安全操作。

        特点:

返回值

true:成功取出元素,element 和 priority 参数被正确赋值。

false:队列为空,element 和 priority 赋为 default(TElement) 和 default(TPriority)

非破坏性检查:

        与 Dequeue() 不同,此方法不会在队列为空时抛出异常,而是通过返回值明确操作结果。

例如:

var queue = new PriorityQueue<char, int>();
queue.Enqueue('A', 3);
queue.Enqueue('B', 1);// 安全出队
if (queue.TryDequeue(out char element, out int priority))
{Console.WriteLine($"出队元素: {element} (优先级: {priority})"); // B (优先级: 1)
}// 队列未空时继续操作
if (queue.TryDequeue(out element, out priority))
{Console.WriteLine($"出队元素: {element} (优先级: {priority})"); // A (优先级: 3)
}// 队列已空时处理
if (!queue.TryDequeue(out element, out priority))
{Console.WriteLine("队列为空!"); // 输出此句Console.WriteLine($"element 的默认值: {element}"); // 输出 '\0'(char 的默认值)Console.WriteLine($"priority 的默认值: {priority}"); // 输出 0(int 的默认值)
}
与 Dequeue() 的对比
方法行为适用场景
Dequeue()直接取出元素,队列为空时抛出异常确定队列非空时简化代码
TryDequeue(...)安全取出元素,通过返回值处理空队列情况

不确定队列状态时避免异常

6.注意事项 

        (1)PriorityQueue<TElement, TPriority> 是 .NET 6 及以上版本中引入的泛型数据结构,仅在 .NET 6、.NET 7、.NET 8 及后续版本中可用。若项目目标框架为旧版本(如 .NET 5、.NET Core 3.1 或更早),则无法直接使用此类型。需通过升级项目框架或寻找替代方案(如第三方库)解决兼容性问题。

        (2)PriorityQueue<TElement, TPriority> 默认允许插入重复元素(即使元素值和优先级均相同)。若需确保队列中元素的唯一性,需自行维护逻辑,例如通过 HashSet<TElement> 跟踪已存在的元素,仅在元素未添加时调用 Enqueue

         (3)默认值陷阱:当队列为空时,TryDequeue 方法会将输出参数设为 TElement 和 TPriority 的默认值(如 int 为 0,引用类型为 null)。需通过返回值判断操作是否成功,避免误用默认值导致逻辑错误。异常风险:直接调用 Dequeue() 或 Peek() 方法时,若队列为空会抛出 InvalidOperationException。建议优先使用 TryDequeue 和 TryPeek 方法,以规避异常风险。

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

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

相关文章

如何查看和验证AWS CloudFront的托管区域ID

在使用AWS Route 53设置DNS记录时,正确识别CloudFront分发的托管区域ID是至关重要的。本文将详细介绍几种查看和验证CloudFront托管区域ID的方法,特别关注中国区CloudFront的特殊情况。 为什么托管区域ID很重要? 托管区域ID是AWS服务中的一个关键标识符。在创建指向CloudF…

kafka整合flume与DStream转换

一、Kafka整合flume cd /opt/software/flume/conf/ vi flume-kafka.conf a1.sourcesr1 a1.sinksk1 a1.channelsc1 a1.sources.r1.typespooldirt a1.sources.r1.spoolDir/root/flume-kafka a1.sinks.k1.typeorg.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.to…

网络通讯【QTcpServer、QTcpSocket、QAbstractSocket】

目录 QTcpServer class简单描述成员函数和信号 QTcpSocket Class详细描述成员函数和信号 QAbstractSocket Class详细描述成员函数和信号成员函数说明文档 QT实现服务器和客户端通讯服务器端&#xff1a;通讯流程原代码 客户端通信流程原代码 QTcpServer class header: #includ…

大模型在肾癌诊疗全流程中的应用研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 国内外研究现状 二、大模型预测肾癌术前情况 2.1 基于影像组学的肾癌良恶性及分级预测 2.1.1 MRI 影像组学模型预测肾透明细胞癌分级 2.1.2 CT 影像深度学习模型鉴别肾肿物良恶性及侵袭性 2.2 大模型对手术风…

网络原理 - 11(HTTP/HTTPS - 2 - 请求)

目录 HTTP 请求&#xff08;Request&#xff09; 认识 URL URL 基本格式 关于 URL encode 认识方法&#xff08;method&#xff09; 1. GET 方法 2. POST 方法 认识请求“报头”&#xff08;header&#xff09; Host Content-Length Content-Type User-Agent&…

实现MySQL高可用性:从原理到实践

目录 一、概述 1.什么是MySQL高可用 2.方案组成 3.优势 二、资源清单 三、案例实施 1.修改主机名 2.安装MySQL数据库&#xff08;Master1、Master2&#xff09; 3.配置mysql双主复制 4.安装haproxy&#xff08;keepalived1、keepalived2&#xff09; 5.安装keepaliv…

CSS学习笔记8——表格

一、表格 1-1、创建表格 在Word文档中&#xff0c;如果要创建表格&#xff0c;只需插入表格&#xff0c;然后设定相应的行数和列数即可。然而在HTML网页中&#xff0c;所有的元素都是通过标签定义的&#xff0c;要想创建表格&#xff0c;就需要使用与表格相关的标签。使用标签…

爬虫学习笔记(一)

目的 通过编写程序爬取互联网上的优质资源 爬虫必须要使用python吗 非也~ 编程语言知识工具&#xff0c;抓取到数据才是目的&#xff0c;而大多数爬虫采用python语言编写的原因是python的语法比较简单&#xff0c;python写爬虫比较简单&#xff01;好用&#xff01;而且pyt…

大厂面试:MySQL篇

前言 本章内容来自B站黑马程序员java大厂面试题和小林coding 博主学习笔记&#xff0c;如果有不对的地方&#xff0c;海涵。 如果这篇文章对你有帮助&#xff0c;可以点点关注&#xff0c;点点赞&#xff0c;谢谢你&#xff01; 1.MySQL优化 1.1 定位慢查询 定位 一个SQL…

C++_数据结构_详解红黑树

✨✨ 欢迎大家来到小伞的大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 小伞的主页&#xff1a;xiaosan_blog 制作不易&#xff01;点个赞吧&#xff01;&#xff01;谢谢喵&#xff01;&…

DNA复制过程3D动画教学工具

DNA复制过程3D动画教学工具 访问工具页面: DNA复制动画演示 工具介绍 我开发了一个交互式的DNA复制过程3D动画演示工具&#xff0c;用于分子生物学教学。这个工具直观展示了&#xff1a; DNA双螺旋结构的解旋过程碱基互补配对原理半保留复制机制完整的复制周期动画 主要特点…

使用阿里云 CDN 保护网站真实 IP:完整配置指南

使用阿里云 CDN 保护网站真实 IP&#xff1a;完整配置指南 一、宝塔面板准备工作1. 确认网站部署状态2. 宝塔中检查网站配置 二、配置阿里云 CDN1. 添加域名到 CDN2. 配置 DNS 解析3. 配置成功确认 三、宝塔面板安全加固&#xff08;隐藏 IP 的关键步骤&#xff09;1. 禁止通过…

PHP经验笔记

isset — 检测变量是否设置,并且不是NULL; 若变量存在且值不为NULL&#xff0c;则返回 TURE 若变量存在且其值为NULL或变量不存在&#xff0c;则返回 FALSE 结论 1. 当变量为空字符串、数值0和布尔值false时&#xff0c;isset全部返回true 2. 当变量不存在和变量存在且值为NULL…

Linux——安装NVM

1. 安装命令 官方地址&#xff1a;https://github.com/nvm-sh/nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash2. 安装完成后执行命令 source ~/.bashrc3. 验证 nvm -v

CentOS 7 磁盘阵列搭建与管理全攻略

CentOS 7 磁盘阵列搭建与管理全攻略 在数据存储需求日益增长的今天&#xff0c;磁盘阵列&#xff08;RAID&#xff09;凭借其卓越的性能、数据安全性和可靠性&#xff0c;成为企业级服务器和数据中心的核心存储解决方案。CentOS 7 作为一款稳定且功能强大的 Linux 操作系统&am…

C++每日训练 Day 18:构建响应式表单与数据验证(初学者友好)

&#x1f4d8; 本篇目标&#xff1a;在前几日协程与事件驱动机制基础上&#xff0c;构建一个响应式表单系统&#xff0c;实现用户输入的异步验证与反馈。通过协程挂起/恢复机制&#xff0c;简化异步逻辑&#xff0c;提升代码可读性。 &#x1f501; 回顾 Day 17&#xff1a;响应…

Vue初步总结-摘自 黑马程序员

本文摘自 bilibili 前端最新Vue2Vue3基础入门到实战项目全套教程&#xff0c;自学前端vue就选黑马程序员&#xff0c;一套全通关&#xff01; 更多详情可参考&#xff1a; https://www.yuque.com/u26161316/pic6n4/heyv8nv8ubfk3fhe?singleDoc# 《Vue》

【基于Qt的QQ音乐播放器开发实战:从0到1打造全功能音乐播放应用】

&#x1f339; 作者: 云小逸 &#x1f91f; 个人主页: 云小逸的主页 &#x1f91f; motto: 要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前&#xff0c;其次就是现在&…

线程池(二):深入剖析synchronized关键字的底层原理

线程池&#xff08;二&#xff09;&#xff1a;深入剖析synchronized关键字的底层原理 线程池&#xff08;二&#xff09;&#xff1a;深入剖析synchronized关键字的底层原理一、基本使用1.1 修饰实例方法1.2 修饰静态方法1.3 修饰代码块 二、Monitor2.1 Monitor的概念2.2 Moni…

Linux CentOS 7 安装Apache 部署html页面

*、使用yum包管理器安装Apache。运行以下命令&#xff1a; sudo yum install httpd *、启动Apache服务 sudo systemctl start httpd *、设置Apache服务开机自启 # 启用开机自启动 sudo systemctl enable httpd# 禁用开机自启动 sudo systemctl disable httpd *、验证Apac…