跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

STL 容器适配器 stack 与 queue 底层模拟及算法实战

STL 容器适配器 stack 和 queue 基于基础容器封装实现特定操作逻辑。深入讲解二者核心概念,手动模拟实现底层逻辑,并通过最小栈、逆波兰表达式等典型算法题展示实际应用,帮助夯实数据结构基础与 STL 设计思想。

BackendPro发布于 2026/3/16更新于 2026/4/284 浏览
STL 容器适配器 stack 与 queue 底层模拟及算法实战

容器适配器概述

STL 中的 stack 和 queue 本质是容器适配器,它们基于基础容器封装实现特定操作逻辑。理解它们的底层机制,有助于我们更好地掌握 STL 设计思想。

什么是容器适配器?

适配器可以理解为'转换器',它能把原本不兼容的对象改造为可以直接使用的形式。容器适配器专门用来包装底层容器(例如 deque、vector),通过屏蔽复杂接口,只暴露栈、队列等特定数据结构的核心操作。

为什么不支持迭代器?

容器适配器的核心目标是限制访问范围:

  • stack:仅允许操作栈顶(LIFO),若暴露迭代器,用户就能遍历所有元素,破坏设计意图。
  • queue:仅允许操作队首/队尾(FIFO),迭代器会打破两端操作的限制。
  • priority_queue:仅允许操作优先级最高的元素,底层存储顺序并非优先级顺序,遍历无意义。

因此,迭代器这种'通用遍历'工具与适配器'限制访问'的目标相悖,二者天生不兼容。

Stack 详解

核心概念

Stack 是一种后进先出(LIFO)的容器适配器。元素的插入和提取只能在容器的一端进行,通常将底层容器的尾部当作栈顶。

它对底层容器的要求包括:empty、back、push_back、pop_back。默认情况下使用 deque,但 vector 和 list 也符合要求。

模拟实现

namespace bit {
template<class T, class Container = std::deque<T>>
class stack {
public:
    // 压栈:将 x 插入栈顶
    void push(const T& x) { _con.push_back(x); }
    
    // 出栈:删除栈顶元素
    void pop() { _con.pop_back(); }
    
    // 获取栈顶元素:返回 const 引用避免拷贝
    const T& top() { return _con.back(); }
    
    // 判断是否为空
    bool empty() { return _con.empty(); }
    
    // 获取元素个数
    size_t size() { return _con.size(); }

private:
    Container _con; // 底层容器,实际存储数据
};
}

这里的 _con 是实际的存储对象,所有操作都委托给它。关于默认成员函数,编译器会自动生成构造、析构等函数,它们会调用底层容器的对应方法,所以无需手动编写。

Queue 详解

核心概念

Queue 是先进先出(FIFO)的容器适配器。元素从队尾入列,从队头出列。

底层容器需支持:empty、size、front、back、push_back、pop_front。默认同样使用 deque。

模拟实现

namespace bit {
template<class T, class Container = std::deque<T>>
class queue {
public:
    // 入队:插入到尾部
    void push(const T& x) { _con.push_back(x); }
    
    // 出队:删除头部元素
    void pop() { _con.pop_front(); }
    
    // 获取队头元素
    const T& front() { return _con.front(); }
    
    // 获取队尾元素
    const T& back() { return _con.back(); }
    
    // 判空
    bool empty() { return _con.empty(); }
    
    // 获取大小
    size_t size() { return _con.size(); }

private:
    Container _con;
};
}

注意 pop() 不返回值,这是为了符合标准库规范,避免误用。

算法实战

1. 最小栈

思路:用一个数据栈存所有元素,另一个最小值栈同步维护当前阶段的最小值。入栈时若新元素小于等于最小值栈顶则压入;出栈时若弹出的是最小值则同步弹出。

class MinStack {
public:
    MinStack() {}
    
    void push(int val) {
        _st.push(val);
        if (_minst.empty() || val <= _minst.top()) {
            _minst.push(val);
        }
    }
    
    void pop() {
        if (_minst.top() == _st.top()) {
            _minst.pop();
        }
        _st.pop();
    }
    
    int top() { return _st.top(); }
    int getMin() { return _minst.top(); }

private:
    std::stack<int> _st;
    std::stack<int> _minst;
};

2. 栈的压入、弹出序列

思路:模拟入栈出栈过程。依次将元素压入栈,若栈顶与出栈数组待匹配元素一致,则弹出并移动指针。最终栈为空即合法。

class Solution {
public:
    bool IsPopOrder(std::vector<int>& pushV, std::vector<int>& popV) {
        std::stack<int> st;
        int pushi = 0, popi = 0;
        while (pushi < pushV.size()) {
            st.push(pushV[pushi++]);
            while (!st.empty() && st.top() == popV[popi]) {
                st.pop();
                popi++;
            }
        }
        return st.empty();
    }
};

3. 逆波兰表达式求值

思路:遇到数字入栈,遇到运算符则弹出两个数运算后将结果压回栈。

class Solution {
public:
    int evalRPN(std::vector<std::string>& tokens) {
        std::stack<int> st;
        for (auto& e : tokens) {
            if (e == "+" || e == "-" || e == "*" || e == "/") {
                int right = st.top(); st.pop();
                int left = st.top(); st.pop();
                switch (e[0]) {
                    case '+': st.push(left + right); break;
                    case '-': st.push(left - right); break;
                    case '*': st.push(left * right); break;
                    case '/': st.push(left / right); break;
                }
            } else {
                st.push(std::stoi(e));
            }
        }
        return st.top();
    }
};

4. 用栈实现队列

思路:双栈法。一个栈负责入队 (push_st),一个栈负责出队 (pop_st)。当 pop_st 为空时,将 push_st 全部倒入 pop_st,此时 pop_st 栈顶即为队头。

class MyQueue {
public:
    void push(int x) { push_st.push(x); }
    
    int pop() {
        if (pop_st.empty()) {
            while (!push_st.empty()) {
                pop_st.push(push_st.top());
                push_st.pop();
            }
        }
        if (pop_st.empty()) return 0;
        int top = pop_st.top();
        pop_st.pop();
        return top;
    }
    
    int peek() {
        if (pop_st.empty()) {
            while (!push_st.empty()) {
                pop_st.push(push_st.top());
                push_st.pop();
            }
        }
        if (pop_st.empty()) return 0;
        return pop_st.top();
    }
    
    bool empty() { return push_st.empty() && pop_st.empty(); }

private:
    std::stack<int> push_st;
    std::stack<int> pop_st;
};

5. 用队列实现栈

思路:始终向非空队列加入元素。出栈时将非空队列的前 n-1 个元素导入空队列,剩下的最后一个即为栈顶。

class MyStack {
public:
    void push(int x) {
        if (!q1.empty()) q1.push(x);
        else q2.push(x);
    }
    
    int pop() {
        if (q1.empty()) {
            while (q2.size() > 1) {
                q1.push(q2.front());
                q2.pop();
            }
            int ret = q2.front();
            q2.pop();
            return ret;
        } else {
            while (q1.size() > 1) {
                q2.push(q1.front());
                q1.pop();
            }
            int ret = q1.front();
            q1.pop();
            return ret;
        }
    }
    
    int top() {
        if (!q1.empty()) return q1.back();
        if (!q2.empty()) return q2.back();
        return 0;
    }
    
    bool empty() { return q1.empty() && q2.empty(); }

private:
    std::queue<int> q1;
    std::queue<int> q2;
};

目录

  1. 容器适配器概述
  2. 什么是容器适配器?
  3. 为什么不支持迭代器?
  4. Stack 详解
  5. 核心概念
  6. 模拟实现
  7. Queue 详解
  8. 核心概念
  9. 模拟实现
  10. 算法实战
  11. 1. 最小栈
  12. 2. 栈的压入、弹出序列
  13. 3. 逆波兰表达式求值
  14. 4. 用栈实现队列
  15. 5. 用队列实现栈
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • KingbaseES SQL 防火墙的工程化实践与性能分析
  • Gemini Pro 提示词最佳实践:多模态与结构化设计指南
  • DeepSeek 深度使用指南:提示词技巧与本地知识库搭建
  • FPGA 摄像头采集处理显示指南:OV5640 至 HDMI 实时显示
  • WebGL 无代码 3D 交互设计平台:翠鸟艺术家技术解析
  • HS-FPN:微小目标检测的频域与空间感知架构
  • 基于 FPGA 的高速多通道数据采集系统设计
  • 程序员接单兼职平台盘点与选择指南
  • Transformer 核心机制解析:自注意力与多头机制
  • Rust 与 WebAssembly 实战:在浏览器与 Node.js 中运行高性能代码
  • KingbaseES ksql 指南:创建与管理索引和视图
  • 优雅降级 vs 渐进增强:前端兼容策略的“道”与“术”
  • 前端通用 AI Rules 定义及主流工具适配指南
  • iOS 新系统兼容适配:UITabBar 液态玻璃效果与 WiFi SSID 获取
  • Python 创意小工具开发指南:从构思到实现
  • 2026 届学位论文 AIGC 检测率标准与应对策略
  • Stable Diffusion 3.5 工业设计实战:产品草图生成系统
  • 基于 Spring Boot 3 + Vue 3 的综合商城系统设计
  • 基于 RISC-V 的智能家居中控系统:硬件、固件与通信全链路实战
  • OpenClaw macOS 本地部署与安装指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online