在C#的集合框架中,Queue和Stack是两种典型的线性数据结构,分别遵循先进先出和后进先出的元素管理规则,适合处理不同的业务场景。Queue队列常用于需要按顺序处理元素的场景,比如消息队列、任务调度等,Stack栈则适合需要回溯操作的场景,比如表达式求值、撤销操作实现等。

C# Queue队列基础用法
Queue的核心特性
Queue是泛型集合类,位于System.Collections.Generic命名空间下,它的核心特性是先进先出,也就是最先添加到队列中的元素会最先被取出。Queue不允许直接通过索引访问元素,只能通过特定的方法操作内部元素。
Queue的常用方法
- Enqueue:向队列的末尾添加一个元素,也就是入队操作
- Dequeue:移除并返回队列开头的元素,也就是出队操作,如果队列为空调用该方法会抛出异常
- Peek:返回队列开头的元素但不移除它,队列为空时调用会抛出异常
- Count:获取队列中当前元素的数量
- Clear:清空队列中的所有元素
- Contains:判断队列中是否包含指定的元素,返回布尔值
Queue代码示例
下面是Queue的基础操作示例,展示入队、出队、遍历等常见操作:
using System;
using System.Collections.Generic;
namespace QueueDemo
{
class Program
{
static void Main(string[] args)
{
// 初始化一个存储int类型的Queue队列
Queue<int> numberQueue = new Queue<int>();
// 入队操作,向队列添加元素
numberQueue.Enqueue(10);
numberQueue.Enqueue(20);
numberQueue.Enqueue(30);
Console.WriteLine("入队后队列元素数量:" + numberQueue.Count); // 输出3
// 查看队首元素但不移除
int peekResult = numberQueue.Peek();
Console.WriteLine("队首元素(Peek):" + peekResult); // 输出10
Console.WriteLine("Peek后队列元素数量:" + numberQueue.Count); // 数量仍为3
// 出队操作,移除并返回队首元素
int dequeueResult = numberQueue.Dequeue();
Console.WriteLine("出队元素(Dequeue):" + dequeueResult); // 输出10
Console.WriteLine("出队后队列元素数量:" + numberQueue.Count); // 输出2
// 判断队列是否包含指定元素
bool hasTwenty = numberQueue.Contains(20);
Console.WriteLine("队列是否包含20:" + hasTwenty); // 输出True
// 遍历队列元素,注意遍历不会移除元素
Console.WriteLine("当前队列所有元素:");
foreach (int num in numberQueue)
{
Console.WriteLine(num);
}
// 清空队列
numberQueue.Clear();
Console.WriteLine("清空后队列元素数量:" + numberQueue.Count); // 输出0
}
}
}
C# Stack栈基础用法
Stack的核心特性
Stack同样位于System.Collections.Generic命名空间下,它的核心特性是后进先出,最后添加到栈中的元素会最先被取出。和Queue一样,Stack也不支持通过索引直接访问元素,只能通过特定方法操作。
Stack的常用方法
- Push:向栈的顶部添加一个元素,也就是入栈操作
- Pop:移除并返回栈顶的元素,也就是出栈操作,栈为空时调用会抛出异常
- Peek:返回栈顶的元素但不移除它,栈为空时调用会抛出异常
- Count:获取栈中当前元素的数量
- Clear:清空栈中的所有元素
- Contains:判断栈中是否包含指定的元素,返回布尔值
Stack代码示例
下面是Stack的基础操作示例,展示入栈、出栈、遍历等常见操作:
using System;
using System.Collections.Generic;
namespace StackDemo
{
class Program
{
static void Main(string[] args)
{
// 初始化一个存储string类型的Stack栈
Stack<string> nameStack = new Stack<string>();
// 入栈操作,向栈添加元素
nameStack.Push("张三");
nameStack.Push("李四");
nameStack.Push("王五");
Console.WriteLine("入栈后栈元素数量:" + nameStack.Count); // 输出3
// 查看栈顶元素但不移除
string peekResult = nameStack.Peek();
Console.WriteLine("栈顶元素(Peek):" + peekResult); // 输出王五
Console.WriteLine("Peek后栈元素数量:" + nameStack.Count); // 数量仍为3
// 出栈操作,移除并返回栈顶元素
string popResult = nameStack.Pop();
Console.WriteLine("出栈元素(Pop):" + popResult); // 输出王五
Console.WriteLine("出栈后栈元素数量:" + nameStack.Count); // 输出2
// 判断栈是否包含指定元素
bool hasLiSi = nameStack.Contains("李四");
Console.WriteLine("栈是否包含李四:" + hasLiSi); // 输出True
// 遍历栈元素,注意遍历不会移除元素
Console.WriteLine("当前栈所有元素:");
foreach (string name in nameStack)
{
Console.WriteLine(name);
}
// 清空栈
nameStack.Clear();
Console.WriteLine("清空后栈元素数量:" + nameStack.Count); // 输出0
}
}
}
Queue和Stack的差异对比
两种数据结构的对比如下:
| 对比维度 | Queue队列 | Stack栈 |
|---|---|---|
| 元素取出规则 | 先进先出,先添加的元素先取出 | 后进先出,后添加的元素先取出 |
| 核心操作 | Enqueue入队、Dequeue出队 | Push入栈、Pop出栈 |
| 适用场景 | 消息处理、任务排队、广度优先搜索 | 撤销操作、表达式求值、深度优先搜索 |
使用注意事项
在使用Queue和Stack时需要注意,调用Dequeue、Pop、Peek方法前最好先判断集合是否为空,避免抛出InvalidOperationException异常。可以通过Count属性判断元素数量,或者使用TryDequeue、TryPop等扩展方法(如果框架版本支持)来安全操作。另外,这两种集合都不是线程安全的,如果在多线程场景下使用,需要额外加锁或者使用线程安全版本的集合类。