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

栈与队列:从底层原理到实际应用

接触数据结构时,栈和队列是绕不开的基础。刚开始总觉得它们操作简单、概念直白,直到实际写代码踩了坑,才发现这两个 "简单结构" 里藏着不少设计巧思。结合学习资料和自己的实践经历,整理了这篇偏复习向的笔记,把核心知识点和避坑点都理清楚。

一、先搞懂核心:本质与特性

栈和队列最核心的区别在于数据访问顺序,这直接决定了它们的应用场景。用生活里的例子类比最容易记:栈像家里摞起来的盘子,只能从最顶上拿放;队列像排队买奶茶,先来的人先拿到饮品。

1. 栈(Stack):后进先出(LIFO)

  • 核心原则:最后插入的元素最先被移除,只有 "栈顶" 一个操作口。
  • 必记操作push(入栈,加在栈顶)、pop(出栈,删栈顶元素)、top(查栈顶元素)、empty(判空)、size(查元素数)。
  • 关键提醒pop操作只删元素不返回值,要拿元素得先⽤top,这是刚开始写代码常搞混的点。

2. 队列(Queue):先进先出(FIFO)

  • 核心原则:最先插入的元素最先被移除,有 "队头"(删)和 "队尾"(加)两个操作口。
  • 必记操作push(入队,加在队尾)、pop(出队,删队头元素)、front(查队头)、back(查队尾),emptysize与栈一致。
  • 关键提醒:和栈一样,pop不返回值,且队列没有top接口,别记混成栈的操作名。

二、深入底层:不是容器,是 "适配器"

这是我学习时的第一个认知误区:一直以为栈和队列是和vectorlist并列的容器,后来才发现它们是容器适配器—— 基于其他容器封装的接口,自己本身不存数据。

1. 底层容器的选择逻辑

C++ 里栈和队列默认用deque(双端队列)做底层,因为deque的头尾操作都很高效。但也能自定义底层容器,不过有严格限制:

操作需求栈(Stack)要求队列(Queue)要求
尾部插入✅ push_back✅ push_back
尾部删除✅ pop_back❌ 不需要
头部删除❌ 不需要✅ pop_front
访问尾部✅ back✅ back
访问头部❌ 不需要✅ front

2. 实战里的选择建议

  • 栈的底层选择:可以用vectorlist。我自己写题时更爱用vector,因为内存连续,缓存命中率高,速度更快;但如果数据量波动大、频繁扩容,list的按需分配内存更有优势。
  • 队列的底层选择:千万别用vectorvector没有pop_front接口,强行模拟头删要移动所有元素,时间复杂度 O (n),完全违背队列的高效需求。实际开发里要么用默认的deque,要么用list,两者头删尾插都是 O (1)。

3. 代码示例:自定义底层容器

// 用vector做底层的栈
stack<int, vector<int>> s_vec;
// 用list做底层的队列
queue<int, list<int>> q_list;
// 默认都是deque,等价于下面这样
stack<int> s; // 等价于stack<int, deque<int>>
queue<int> q; // 等价于queue<int, deque<int>>

三、避坑指南:这些错误别再犯

刚开始写栈和队列的代码时,踩过不少 "低级错误",后来发现都是没吃透特性导致的,整理几个高频坑:

1. 空容器操作:直接崩溃的重灾区

栈和队列的poptopfrontback操作都不能在空容器上执行,会触发未定义行为(大概率崩溃)。必须先判空再操作,这是铁律。

// 错误写法
stack<int> s;
s.pop(); // 空栈pop,直接崩
cout << s.top(); // 同样危险// 正确写法
if (!s.empty()) {cout << s.top();s.pop();
}

2. 遍历误区:没有迭代器,别硬遍历

栈和队列设计的核心是 "限制访问顺序",所以 STL 里根本没给它们迭代器,没法用for循环遍历所有元素。如果非要遍历,只能通过top/front+pop的方式,把元素一个个取出来处理,但这样会清空容器,记得提前备份。

3. 优先级队列:别和普通队列搞混

priority_queue虽然在queue头文件里,但本质是堆结构,不是普通队列。它的 "出队" 顺序是按优先级(默认大的优先),不是插入顺序。比如插入 3、1、5,出队顺序是 5、3、1,这点刚开始很容易记混。

四、实用主义:记牢应用场景

数据结构的价值体现在应用上,记住栈和队列的典型场景,做题和开发时能快速选对工具。

1. 栈的用武之地

  • 回溯与撤销:浏览器的后退功能、编辑器的 Ctrl+Z,本质都是把操作记录压栈,撤销时弹栈恢复。
  • 括号匹配:经典算法题,遇到左括号压栈,遇到右括号就弹栈比对,最后栈空则匹配成功。
  • 递归实现:递归函数调用时,系统会自动用栈保存上下文,递归太深栈溢出就是这个原因。
  • 表达式求值:比如计算 "3+4*2",用栈能处理运算符的优先级。

2. 队列的用武之地

  • 任务调度:打印机的任务队列、多线程的任务池,都要保证先提交的任务先执行。
  • BFS 遍历:图和树的广度优先搜索必须用队列,比如求二叉树的层序遍历、迷宫的最短路径。
  • 消息队列:应用间通信的消息传递,用队列能解耦生产者和消费者,保证消息顺序。

我自己在做 "二叉树层序遍历" 时,刚开始用了栈,结果出来的是深度优先的顺序,后来才反应过来 BFS 必须用队列,这就是没把场景和结构对应好的教训。

五、复习小结:一张表理清核心区别

最后整理成对比表,复习时看一眼就能回忆起关键差异:

特性栈(Stack)队列(Queue)
核心原则后进先出(LIFO)先进先出(FIFO)
操作口仅栈顶队头(删)、队尾(加)
关键操作top () 访问栈顶front ()/back () 访队头 / 尾
默认底层容器dequedeque
能否用 vector 底层可以不建议(无 pop_front)
典型应用括号匹配、递归、撤销BFS、任务调度、消息队列
时间复杂度(核心操作)O(1)O(1)

其实栈和队列的知识点不算复杂,但细节决定成败。比如忘记判空就操作、选错底层容器、把优先级队列当普通队列用,这些小错误都可能导致程序崩溃。复习时重点抓 "特性 - 底层 - 应用" 的逻辑链,再把避坑点记牢,基本就不会出问题了

http://www.dtcms.com/a/512817.html

相关文章:

  • 法人变更在哪个网站做公示wordpress扒主题代码
  • 【Qt】定时器--滚动相册
  • Qt 与 VS Studio 结合使用
  • 咸宁做网站的公司那家便宜闵行网站制作哪里有
  • 高压输电线背景下无人机检测输电线和周围树木以及计算两者之间的距离
  • MySQL锁机制详解
  • 用户网站模板厦门唯一官方网站
  • 介绍化工项目建设和招聘的网站做网站app要注册哪类商标
  • milvus容器restart不成功,但docker仍在running问题排查
  • 女的和男的做那个视频网站广西网站建设公司电话
  • 织梦网站首页模板更换重要新闻头条
  • ABAP 静态代码分析 - 语法分析
  • 【VPX315】基于 3U VPX 总线架构的 JFMQL100TAI + FT-M6678 智能信号处理平台
  • 建个什么网站赚钱大连发布: 大连发布
  • 南京网站建设工作室企业网站推广是不是必要的
  • 网站制作html代码网站开发工作量
  • Sprintf Boot 之 Nacos 配置中心实践(spring.config.import=optional:nacos:)
  • 东莞行业网站建设中国电子商务中心官网
  • 山东住房和城乡建设厅网站登陆怎么打广告宣传自己的产品
  • 网站建设公司营业执照图片免费图片在线制作
  • 参加科学大会(dijkstra(堆优化版))
  • 百度上如何做优化网站wordpress 目录权限设置
  • 涪陵建设工程信息网站除了红动中国还有哪些设计网站
  • JVM虚拟机入门到实战(持续更新中)
  • 苏州网站建设与网络营销网络销售的好处和意义
  • 免费wordpress主题分享seo网站建站公司的主页
  • 外贸网站宗旨网站建设包括哪些方面
  • 什么外设选择开漏,什么外设选择推挽?
  • HTML 标签及推荐嵌套结构
  • 优先算法专题十二——栈