-
队列(Queue)与栈(Stack)
队列(Queue)与栈(Stack)
概述
队列和栈是两种经典的线性数据结构,核心区别在于元素的存取顺序:
队列(Queue):先进先出(FIFO,First-In-First-Out),类似排队买票,先到先得;
栈(Stack):后进先出(LIFO,Last-In-First-Out),类似叠盘子,最后放的先拿。
它们都是泛型集合(Queue
-
队列(Queue
):先进先出
队列的核心操作是入队(Enqueue)和出队(Dequeue),支持查vb.net教程C#教程python教程SQL教程access 2010教程看队首元素(不移除),适合任务排队、消息调度等场景。
1.1 实例代码:模拟打印机任务排队
csharp
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 1. 初始化队列:存储打印任务(字符串类型)
Queue<string> printQueue = new Queue<string>();
// 2. 入队:添加打印任务到队尾
printQueue.Enqueue("报告.docx");
printQueue.Enqueue("简历.pdf");
printQueue.Enqueue("照片.png");
// 3. 查看队首元素(不移除)
string firstTask = printQueue.Peek();
Console.WriteLine($"当前队首任务:{firstTask}"); // 输出:报告.docx
// 4. 遍历队列(保持入队顺序)
Console.WriteLine("
队列中的任务:");
foreach (string task in printQueue)
{
Console.WriteLine($"- {task}"); // 输出:报告.docx、简历.pdf、照片.png
}
// 5. 出队:处理队首任务(移除并返回)
string processedTask = printQueue.Dequeue();
Console.WriteLine($"
已处理任务:{processedTask}"); // 输出:报告.docx
// 6. 安全出队:避免空队列异常
bool hasNext = printQueue.TryDequeue(out string nextTask);
if (hasNext)
{
Console.WriteLine($"安全处理任务:{nextTask}"); // 输出:简历.pdf
}
// 7. 查看剩余任务数
Console.WriteLine($"剩余任务数:{printQueue.Count}"); // 输出:1
}
}
1.2 逐行讲解
初始化:Queue
入队:Enqueue将元素添加到队列末尾(类似排队尾);
查看队首:Peek获取队列第一个元素,但不改变队列状态;
遍历:foreach按入队顺序遍历(队列保持FIFO特性);
出队:Dequeue移除并返回队首元素(处理完任务就从队列删除);
安全出队:TryDequeue避免空队列抛出InvalidOperationException,返回是否成功,成功则通过out参数取元素;
任务数:Count属性获取当前队列元素数量。
1.3 基础知识拓展
内部实现
Queue
线程安全
多线程场景下用ConcurrentQueue
csharp
ConcurrentQueue<string> safeQueue = new ConcurrentQueue<string>();
safeQueue.Enqueue("任务1");
bool success = safeQueue.TryDequeue(out string task);
适用场景
任务调度(如后台打印任务、异步任务队列);
消息队列(生产者-消费者模式);
广度优先搜索(BFS)算法。
-
栈(Stack
):后进先出
栈的核心操作是入栈(Push)和出栈(Pop),支持查看栈顶元素(不移除),适合撤销操作、表达式计算等场景。
2.1 实例代码:模拟浏览器后退功能
csharp
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 1. 初始化栈:存储浏览历史(URL字符串)
Stack<string> browserHistory = new Stack<string>();
// 2. 入栈:添加最新浏览记录到栈顶
browserHistory.Push("https://www.baidu.com");
browserHistory.Push("https://www.github.com");
browserHistory.Push("https://www.csdn.net");
// 3. 查看栈顶元素(不移除)
string currentPage = browserHistory.Peek();
Console.WriteLine($"当前页面:{currentPage}"); // 输出:csdn.net
// 4. 遍历栈:从栈顶到栈底(逆序入栈顺序)
Console.WriteLine("
浏览历史(从新到旧):");
foreach (string url in browserHistory)
{
Console.WriteLine($"- {url}"); // 输出:csdn、github、baidu
}
// 5. 出栈:后退到上一页(移除栈顶)
string backPage = browserHistory.Pop();
Console.WriteLine($"
后退离开:{backPage}"); // 输出:csdn.net
Console.WriteLine($"当前页面:{browserHistory.Peek()}"); // 输出:github
// 6. 安全出栈:避免空栈异常
bool hasPrev = browserHistory.TryPop(out string prevPage);
if (hasPrev)
{
Console.WriteLine($"安全后退到:{prevPage}"); // 输出:github
Console.WriteLine($"当前页面:{browserHistory.Peek()}"); // 输出:baidu
}
// 7. 剩余记录数
Console.WriteLine($"剩余历史数:{browserHistory.Count}"); // 输出:1
}
}
2.2 逐行讲解
初始化:Stack
入栈:Push将元素添加到栈顶(最新记录在最上面);
查看栈顶:Peek获取栈顶元素(当前页面),不改变栈状态;
遍历:foreach按栈顶到栈底顺序遍历(因为栈是LIFO);
出栈:Pop移除并返回栈顶元素(后退操作,离开当前页面);
安全出栈:TryPop避免空栈抛出异常,返回是否成功;
记录数:Count获取剩余元素数量。
2.3 基础知识拓展
内部实现
Stack
经典应用
撤销功能:如Word的Ctrl+Z,每一步操作入栈,撤销时出栈;
括号匹配:判断字符串"(())[]"是否合法,遇到左括号入栈,右括号则出栈匹配;
表达式求值:计算后缀表达式(如3 4 + 5 *),数字入栈,运算符则弹出两个数字计算后再入栈;
深度优先搜索(DFS):如二叉树遍历,用栈模拟递归。
3.队列与栈的对比
| 特性 |
队列(Queue |
栈(Stack |
|---|---|---|
| 存取顺序 | 先进先出(FIFO) | 后进先出(LIFO) |
| 核心操作 | Enqueue/Dequeue | Push/Pop |
| 查看顶部元素 | Peek(队首) | Peek(栈顶) |
| 遍历顺序 | 入队顺序 | 栈顶到栈底顺序 |
| 典型应用 | 任务排队、消息队列 | 撤销操作、括号匹配 |
总结
队列和栈是基础且实用的数据结构:
队列:按顺序处理场景,核心FIFO;
栈:逆序处理场景,核心LIFO;
两者均不支持随机访问,操作集中在“头部”(队首/栈顶);
优先使用泛型版本(Queue
掌握这两种结构,能解决很多常见编程问题,比如任务调度、算法实现等。
(本节完)
下一章:泛型与集合进阶
(深入讲解泛型原理、自定义集合等内容)
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49382.html










