C++ STL—— stack 和 queue

一、前言:为什么需要 Stack 和 Queue?

在 C++ 的 STL(Standard Template Library)中,vectorlistdeque 等容器提供了灵活的数据存取方式,但有时我们只需要**"只进不出"(Stack)或"只进只出"**(Queue)的数据结构来简化代码逻辑。

  • Stack(栈):遵循**后进先出(LIFO)**原则。想象一摞盘子,最后放上去的盘子最先拿下来。
  • Queue(队列):遵循**先进先出(FIFO)**原则。想象排队买票,最先到的人最先买到票。

这两者都是基于 容器适配器(Container Adaptor) 实现的,即它们封装了底层容器(通常是 dequevector),只暴露有限的接口以满足特定的使用场景[[1]][[2]][[3]]。


二、Stack(栈)的详细介绍

1. 栈的特性与底层实现

  • 特性:只允许在**栈顶(Top)**进行插入和删除操作。
  • 底层容器 :默认使用 deque,但也可以显式指定为 vectorlist(只要底层容器支持 back(), push_back(), pop_back())[[4]][[5]][[6]]。

2. 常用成员函数

cpp 复制代码
stack<int> s;   // 声明一个存放int类型的栈

s.empty();     // 判断栈是否为空,返回bool
s.size();      // 返回栈中元素的个数,返回size_t
s.top();       // 访问栈顶元素,返回对栈顶元素的引用
s.push(val);   // 将元素压入栈顶
s.pop();       // 弹出栈顶元素(注意:pop()不返回值,仅删除)
s.emplace(args...); // 直接在栈顶构造元素(C++11)

注意 :栈不支持遍历(没有迭代器),只能通过 top()pop() 访问元素[[7]][[8]][[9]]。

3. 典型应用场景

  • 表达式求值:中缀表达式转后缀表达式(逆波兰记法)[[10]]。
  • 递归模拟:手动管理函数调用栈,防止栈溢出。
  • 撤销功能:如编辑器的"撤销"操作,最近的操作最先撤销。

三、Queue(队列)的详细介绍

1. 队列的特性与底层实现

  • 特性 :只能在**队尾(Back)插入,在队头(Front)**删除。
  • 底层容器 :默认使用 deque,因为 deque 支持在两端高效插入删除[[11]][[12]][[13]]。

2. 常用成员函数

cpp 复制代码
queue<int> q;    // 声明一个存放int类型的队列

q.empty();      // 判断队列是否为空,返回bool
q.size();       // 返回队列中元素的个数,返回size_t
q.front();      // 访问队首元素,返回对队首元素的引用
q.back();       // 访问队尾元素,返回对队尾元素的引用
q.push(val);    // 将元素加入队尾
q.pop();        // 弹出队首元素(注意:pop()不返回值,仅删除)
q.emplace(args...); // 直接在队尾构造元素(C++11)

注意 :和栈一样,队列也不支持遍历(没有迭代器),只能通过 front()pop() 访问元素[[14]][[15]][[16]]。

3. 典型应用场景

  • 广度优先搜索(BFS):在图论算法中,使用队列来层层遍历节点[[17]]。
  • 任务调度:如操作系统的进程调度,最先到达的任务最先执行。
  • 缓存实现:如 LRU 缓存策略中的队列管理。

四、Stack 与 Queue 的对比

维度 Stack (栈) Queue (队列)
原则 LIFO(后进先出) FIFO(先进先出)
主要操作 push, pop, top push, pop, front, back
使用场景 递归、撤销、表达式求值 BFS、任务调度、缓存
底层容器 默认 deque,可选 vector/list 默认 deque
是否支持遍历

五、实战代码演示

以下代码展示了 stackqueue 的基本使用方法,适合放在 CSDN 博客中作为示例代码块。

1. Stack 示例:整数入栈与出栈

cpp 复制代码
#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> s; // 声明一个栈

    // 入栈操作
    for (int i = 0; i < 5; ++i) {
        s.push(i);
        cout << "压入: " << i << endl;
    }

    // 出栈操作
    while (!s.empty()) {
        cout << "弹出: " << s.top() << endl;
        s.pop();
    }

    return 0;
}

运行结果:

复制代码
压入: 0
压入: 1
压入: 2
压入: 3
压入: 4
弹出: 4
弹出: 3
弹出: 2
弹出: 1
弹出: 0

2. Queue 示例:整数入队与出队

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> q; // 声明一个队列

    // 入队操作
    for (int i = 0; i < 5; ++i) {
        q.push(i);
        cout << "入队: " << i << endl;
    }

    // 出队操作
    while (!q.empty()) {
        cout << "出队: " << q.front() << endl;
        q.pop();
    }

    return 0;
}

运行结果:

复制代码
入队: 0
入队: 1
入队: 2
入队: 3
入队: 4
出队: 0
出队: 1
出队: 2
出队: 3
出队: 4

六、总结

stackqueue 虽然功能单一,但正因为它们的单向操作特性,使得代码更加简洁且效率更高。在日常开发中,了解它们的底层原理(如为什么默认使用 deque)以及它们的适用场景,可以帮助你写出更高效、更符合需求的代码。

通过本篇博客的介绍,你现在应该能熟练掌握这两个容器的基本用法,并能在合适的地方应用它们来解决实际问题了。[[18]][[19]][[20]]

相关推荐
小年糕是糕手2 小时前
【35天从0开始备战蓝桥杯 -- Day7】
开发语言·jvm·数据库·c++·蓝桥杯
网络点点滴2 小时前
customRef的强大之处
开发语言·前端·javascript
柒.梧.2 小时前
深入理解AQS:Java并发编程的核心基石
java·开发语言
磊 子2 小时前
类和对象—>析构+拷贝+运算符重载
开发语言·c++·算法
清风徐来QCQ2 小时前
js中的常用api
开发语言·javascript·ecmascript
leo__5202 小时前
基于Matlab和CPLEX的2变量机组组合调度程序
开发语言·matlab
csbysj20202 小时前
CSS 伪类详解
开发语言
Reisentyan2 小时前
[backend]GoLang Learn Data Day 2
开发语言·后端·golang
困死,根本不会8 小时前
Kivy+Buildozer 打包 APK 踩坑:python-for-android 克隆失败
开发语言·php·kivy