C++容器:stack、queue、deque 基本用法详解

C++ 容器详解:stack、queue、deque 基本用法与对比

在 C++ STL 中,std::stackstd::queuestd::deque 是非常常用的容器,但它们定位和能力有明显区别。

  • stackqueue容器适配器(container adapter),它们本身不存储数据,而是基于底层容器(默认是 deque)提供特定接口限制。
  • deque 是真正的序列容器,功能最强大,支持两端高效操作。

下面从使用方式、接口、底层实现、适用场景进行详细对比和代码演示。

1. 三者快速对比表

特性std::stackstd::queuestd::deque
数据结构语义LIFO(后进先出)栈FIFO(先进先出)队列双端队列(Double-ended queue)
默认底层容器dequedeque—(本身就是容器)
可自定义底层容器是(deque/list/vector)是(deque/list)
两端操作仅顶端入尾、出头两端都高效
随机访问 [] / at()不支持不支持支持(O(1))
迭代器遍历不支持不支持支持(随机访问迭代器)
典型场景表达式求值、DFS、函数调用栈BFS、任务队列、打印队列需要两端操作 + 随机访问的场景
头文件<stack><queue><deque>

2. std::deque —— 最灵活的双端队列

deque 是真正的基础容器,支持:

  • 两端高效插入/删除(O(1) 均摊)
  • 随机访问(O(1)
  • 中间插入/删除较慢(O(n)

基本用法示例

#include <iostream>
#include <deque>
#include <string>

int main() {
    std::deque<int> dq;

    // 两端插入
    dq.push_back(10);   // 尾部插入
    dq.push_back(20);
    dq.push_front(5);   // 头部插入
    dq.push_front(1);

    // 当前内容:1 5 10 20
    std::cout << "front = " << dq.front() << ", back = " << dq.back() << "\n";

    // 随机访问
    std::cout << "第2个元素: " << dq[1] << "\n";          // 5
    std::cout << "第3个元素: " << dq.at(2) << "\n";       // 10(带边界检查)

    // 遍历(支持范围for、迭代器)
    std::cout << "遍历: ";
    for (int x : dq) std::cout << x << " ";
    std::cout << "\n";

    // 两端删除
    dq.pop_front();   // 删除 1
    dq.pop_back();    // 删除 20

    // 清空判断
    while (!dq.empty()) {
        std::cout << "弹出: " << dq.front() << "\n";
        dq.pop_front();
    }

    return 0;
}

deque 常用成员函数

  • push_back(), pop_back()
  • push_front(), pop_front()
  • front(), back()
  • operator[], at()
  • size(), empty(), clear()
  • resize(), reserve()(效果不如 vector 明显)

3. std::stack —— 经典栈(LIFO)

接口非常精简,只允许从栈顶操作。

基本用法

#include <iostream>
#include <stack>

int main() {
    std::stack<std::string> s;

    // 压栈
    s.push("main");
    s.push("funcA");
    s.push("funcB");

    std::cout << "栈大小: " << s.size() << "\n";      // 3

    // 访问栈顶(不弹出)
    std::cout << "当前栈顶: " << s.top() << "\n";     // funcB

    // 出栈
    s.pop();   // 移除 funcB
    std::cout << "出栈后栈顶: " << s.top() << "\n";   // funcA

    // 清空栈
    while (!s.empty()) {
        std::cout << "弹出: " << s.top() << "\n";
        s.pop();
    }

    return 0;
}

注意stack 没有 clear(),也没有迭代器,不能遍历。

自定义底层容器(很少用)

std::stack<int, std::vector<int>> vec_stack;   // 用 vector 实现栈
std::stack<int, std::list<int>>   list_stack;  // 用 list 实现栈

4. std::queue —— 经典队列(FIFO)

只允许队尾入、队首出。

基本用法

#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    // 入队
    q.push(100);
    q.push(200);
    q.push(300);

    std::cout << "队首: " << q.front() << "\n";   // 100
    std::cout << "队尾: " << q.back()  << "\n";   // 300

    // 出队
    q.pop();   // 移除 100
    std::cout << "出队后队首: " << q.front() << "\n";  // 200

    // 遍历清空
    std::cout << "队列元素: ";
    while (!q.empty()) {
        std::cout << q.front() << " ";
        q.pop();
    }
    std::cout << "\n";

    return 0;
}

注意:同样没有迭代器、没有 clear(),只能从两端访问 front/back

自定义底层容器

std::queue<int, std::list<int>> list_queue;   // 用 list 实现队列(较少用)

5. 选择建议总结(实际工程中怎么选)

场景推荐容器理由
只需要经典栈(括号匹配、DFS、单调栈)std::stack接口最清晰,表达意图最强
只需要经典队列(BFS、任务队列)std::queue接口最清晰,防止误用
需要两端都频繁插入/删除std::deque两端 O(1),且支持随机访问
需要两端操作 + 偶尔随机访问std::deque比 vector 更适合频繁头插
追求极致尾部性能 + 内存连续std::vector尾部最快,缓存友好,但头插很慢
频繁任意位置插入/删除std::listO(1) 任意位置插入,但无随机访问

最常见的选择路径

  • 简单栈 → stack
  • 简单队列 → queue
  • 需要两端高效操作,或不确定未来需求 → 直接用 deque
  • 追求尾部极致性能 + 内存连续 → vector

希望这篇详解能帮你清晰地区分和正确使用这三个容器!
如果想看更具体的应用场景(单调栈、滑动窗口、双端 BFS 等),可以继续告诉我。

文章已创建 4547

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部