C# 中的栈、队列和优先级队列

C#/CSHARP教程 2025-11-05

Stack`List`QueuePriorityQueue`Data` 是 C# 中用于高效存储、组织和管理数据的基本数据结构。
它们不仅有助于解决算法难题,而且在实际应用中也极其重要,例如在不同的工作流中进行搜索、任务排序、数据插入、删除和更新等操作。
本文将介绍每种数据结构的主要特性,解释其工作原理,并展示实际应用场景,以帮助读者加深记忆和理解。
那么,让我们开始探讨 C# 中的这些重要数据结构吧。

AStack代表一个后进先出 ( LIFO
) 集合。 这意味着最后添加的元素将最先被移除。

构造函数

构造函数描述
Stack()创建一个空栈。
Stack(int capacity)创建一个具有初始内部容量的堆栈。当已知预期大小时非常有用。
Stack(IEnumerable collection)创建一个堆栈,其中项目是从另一个集合复制的(最后一个元素成为顶部)。

核心运营

成员描述例子
Push(T item)将物品添加到顶部stack.Push("A");
Pop()移除并返回最顶层元素。如果为空则抛出异常。var item = stack.Pop();
Peek()返回顶部元素,但不将其移除。如果为空,则抛出异常。var item = stack.Peek();
TryPop(out T result)安全弹出(如果为空则返回 false)if(stack.TryPop(out var value)){...}
TryPeek(out T result)安全查看(如果为空则返回 false)if(stack.TryPeek(out var value)){...}

实用方法

成员描述
Count栈中元素的数量
Clear()移除所有物品
Contains(T item)检查堆栈中是否包含给定的元素
ToArray()返回一个按后进先出 (LIFO) 顺序排列的新数组
GetEnumerator()遍历栈(栈顶→栈底)
TrimExcess()多次删除后降低内存占用。

例子

    Stack stack = new();

    stack.Push("First");

    stack.Push("Second");

    stack.Push("Third");

    Console.WriteLine("Top of the stack: " + stack.Peek());

    Console.WriteLine("Removing items:");

    while (stack.Count > 0)

        Console.WriteLine(stack.Pop());

    Console.WriteLine("Stack empty? " + (stack.Count == 0));

输出

Top of the stack: ThirdRemoving items:ThirdSecondFirstStack empty? True

栈的工作原理

队列

AQueue表示一个FIFO(先进先出)集合。
第一个插入的元素也是第一个被移除的元素。

构造函数

构造函数描述
Queue()创建一个空队列。
Queue(int capacity)创建一个具有预定义容量的队列。
Queue(IEnumerable collection)初始化一个包含元素的队列,其中第一个元素成为队列的队首。

核心运营

成员描述例子
Enqueue(T item)在背面(尾部)添加物品。queue.Enqueue("A");
Dequeue()移除并返回最前面的物品。如果为空则抛出异常。var item = queue.Dequeue();
Peek()退回前面的物品,无需将其移除。var item = queue.Peek();
TryDequeue(out T result)安全出队if(queue.TryDequeue(out var x)) { ... }
TryPeek(out T result)安全偷窥if(queue.TryPeek(out var x)) { ... }

实用方法

成员描述
Count元素数量
Contains(T item)检查该物品是否存在
ToArray()按先进先出 (FIFO) 顺序退回物品
Clear()移除所有元素
GetEnumerator()遍历队列头部 → 尾部
EnsureCapacity(int capacity)确保足够的内部存储空间,避免调整大小
TrimExcess()减少未使用的内存

代码:

Queue queue = new();queue.Enqueue("First");queue.Enqueue("Second");queue.Enqueue("Third");Console.WriteLine("Front of the queue: " + queue.Peek());Console.WriteLine("Processing queue:");while (queue.Count > 0)

    Console.WriteLine(queue.Dequeue());Console.WriteLine("Queue empty? " + (queue.Count == 0));

输出

Front of the queue: FirstProcessing queue:FirstSecondThirdQueue empty? True

队列的工作原理

优先级队列

APriorityQueue类似于队列,不同之处在于元素移除基于优先级而非插入顺序。
默认情况下,它的行为类似于最小堆(优先级值越低,优先级越高)。

类型:

PriorityQueue
  • TElement→ 你存储的值

  • TPriority→ 决定处理顺序(默认情况下,数字越小优先级越高)

构造函数:

承包商描述
PriorityQueue()创建一个空的优先级队列
PriorityQueue(int initialCapacity)预先分配容量以减少调整规模
PriorityQueue(IEnumerable<(TElement,TPriority)> items)创建包含指定项的队列
PriorityQueue(IEnumerable<(TElement,TPriority)> items, IComparer? priorityComparer)相同,但允许自定义优先级逻辑

核心方法

成员描述例子
Enqueue(TElement element, TPriority priority)添加一个元素及其优先级queue.Enqueue("Task", 2);
Dequeue()移除并返回优先级最高的元素var item = queue.Dequeue();
Peek()返回优先级最高的元素,而不进行移除操作。var item = queue.Peek();
TryDequeue(out TElement element, out TPriority priority)安全出队if(queue.TryDequeue(out var e, out var p)) {...}
TryPeek(out TElement element, out TPriority priority)安全偷窥if(queue.TryPeek(out var e, out var p)) {...}

实用方法

成员描述
Count物品数量
Clear移除所有元素
EnsureCapacity(int capacity)预先分配内存
TrimExcess()减少内存占用
EnqueueDequeue(element, priority)插入项目,然后移除优先级最高的项目。
UnorderedItems退回内部物品,顺序不限

代码:

PriorityQueue queue = new();queue.Enqueue("Fix critical bug", 1);queue.Enqueue("Team meeting", 2);queue.Enqueue("Review PR", 3);Console.WriteLine($"Count: {queue.Count}");Console.WriteLine($"Peek: {queue.Peek()}");if (queue.TryDequeue(out string? task, out int priority))

    Console.WriteLine($"Dequeued: {task} (Priority {priority})");queue.EnqueueRange([

    ("Refactor service", 4),

    ("Write documentation", 5)]);string removed = queue.EnqueueDequeue("Urgent hotfix", 0);Console.WriteLine($"Removed during EnqueueDequeue: {removed}");Console.WriteLine("nRemaining items by priority:");while (queue.TryDequeue(out string? t, out int p))

    Console.WriteLine($"→ {t} (p={p})");queue.TrimExcess();

输出

Count: 3Peek: Fix critical bugDequeued: Fix critical bug (Priority 1)Removed during EnqueueDequeue: Urgent hotfixRemaining items by priority:→ Team meeting (p=2)→ Review PR (p=3)→ Refactor service (p=4)→ Write documentation (p=5)

优先级队列的工作原理

将优先级队列转换为最大堆

要在优先级队列中返回最大值而不是最小值,您可以创建一个自定义比较器:

var queue = new PriorityQueue( comparer: Comparer.Create((x, y) => y.CompareTo(x)));

例子:

var queue = new PriorityQueue( comparer: Comparer.Create((x, y) => y.CompareTo(x)));queue.Enqueue("Low importance", 1);queue.Enqueue("Medium importance", 5);queue.Enqueue("High importance", 10);while (queue.TryDequeue(out string? task, out int priority))

    Console.WriteLine($"{task} (priority {priority})");
High importance (priority 10)Medium importance (priority 5)Low importance (priority 1)

栈、队列和优先级队列(快速比较)

结构订单规则核心运营示例用例
LIFO(后进先出)推/弹/尿撤销系统、调用栈、DFS
队列先进先出 (FIFO)入队/出队/查看调度、任务处理、广度优先搜索
优先级队列基于优先级的排序入队(元素,优先级) / 出队工作调度、人工智能路径规划、医院分诊

真实案例

Stack - 撤销历史记录

在文本编辑器中输入内容时,每个操作都会被添加到历史记录栈中。
如果用户按下撤销按钮,我们会弹出最后一个操作。

var undoStack = new Stack();Type("Hello");Type("Hello World");Type("Hello World!");Undo(); // removes "Hello World!"Undo(); // removes "Hello World"return;void Undo(){

    if (undoStack.TryPop(out string? lastAction))

        Console.WriteLine($"Undo → removed: {lastAction}");}void Type(string text){

    undoStack.Push(text);

    Console.WriteLine($"Typed: {text}");}

队列 - 打印队列

打印队列(打印机按到达顺序处理作业)

var printQueue = new Queue();AddPrintJob("Report.pdf");AddPrintJob("Invoice.docx");AddPrintJob("Presentation.pptx");ProcessNextJob(); // ReportProcessNextJob(); // InvoiceProcessNextJob(); // Presentationreturn;void ProcessNextJob(){

    if (printQueue.TryDequeue(out string? job))

        Console.WriteLine($"Printing: {job}");}void AddPrintJob(string document){

    printQueue.Enqueue(document);

    Console.WriteLine($"Added: {document}");}

PriorityQueue - 医院急诊室分诊

医院急诊室分诊:
病人不是按到达顺序就诊,而是按病情严重程度就诊。

var erQueue = new PriorityQueue(

    comparer: Comparer.Create((a, b) => a.CompareTo(b)) // lower value = higher priority);erQueue.Enqueue("Head trauma", 1);erQueue.Enqueue("Broken arm", 4);erQueue.Enqueue("High fever", 3);erQueue.Enqueue("Cardiac arrest", 0);Console.WriteLine("Patients being treated:");while (erQueue.TryDequeue(out string? patient, out int severity))

    Console.WriteLine($"{patient} (severity {severity})");