跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 深入理解 stack、queue 及 priority_queue 实现原理

C++ 标准库中的 stack、queue 和 priority_queue 属于容器适配器而非独立容器。详细解析了这三种数据结构的底层原理、常用接口及模拟实现。重点探讨了基于 deque 的栈队列机制,以及优先队列堆结构的大顶堆与小顶堆配置方法。结合最小栈、逆波兰表达式及 K 大元素等经典算法题,展示了实际应用场景。最后剖析了 deque 双端队列的内存布局及其作为默认底层容器的优势。

w795471发布于 2026/3/24更新于 2026/10/25111 浏览
C++ 深入理解 stack、queue 及 priority_queue 实现原理

C++ 标准库容器适配器详解

在 C++ STL 中,stack、queue 和 priority_queue 是非常常用的数据结构。它们虽然名字像容器,但实际上属于容器适配器。这意味着它们不是直接管理内存的底层容器,而是对其他容器(如 vector、deque、list)的接口进行了封装,提供了特定的操作方式。

一、Stack:后进先出

1. Stack 介绍

stack 遵循后进先出(LIFO)原则。默认情况下,它使用 deque 作为底层容器,但也可以指定 vector 或 list。头文件为 <stack>。

Stack 结构示意

2. Stack 常用接口

函数说明接口说明
stack()构造空的栈
empty()检测 stack 是否为空
size()返回 stack 中元素的个数
top()返回栈顶元素的引用
push()将元素 val 压入 stack 中
pop()将 stack 中尾部的元素弹出

3. 实战案例:最小栈 (Min Stack)

LeetCode 155 题要求设计一个支持 push、pop、top 以及获取最小值 getMin 操作的栈,且所有操作的时间复杂度必须是 O(1)。

思路: 我们可以维护两个栈:主栈 st 用于存储数据,辅助栈 minst 用于记录当前状态下的最小值。当 st 插入新元素时,如果 minst 为空或者新元素小于等于 minst 的栈顶,则同步压入 minst。弹出时,如果 st 的栈顶等于 minst 的栈顶,说明当前最小值即将被移除,minst 也要同步弹出。

代码实现:

class MinStack {
public:
    MinStack() {}
    
    void push(int val) { 
        _st.push(val);
        // 如果 minst 为空或者 要插入的值小于 minst 的栈顶元素就插入
        if (_minst.empty() || val <= _minst.top()) 
            _minst.push(val);
    }
    
    void pop() {
        // 如果删除的值和 minst 中的值相等,同时删,否则只删 st
        if (!_st.empty() && _st.top() == _minst.top()) 
            _minst.pop(); 
        if (!_st.empty()) _st.pop();
    }
    
    int top() {
        return _st.top();
    }
    
    int getMin() {
        return _minst.top();
    }
private:
    stack<int> _st;
    stack<int> _minst;
};

优化思考: 如果在插入大量重复的最小值时,minst 会占用额外空间。可以定义一个结构体,包含 val 和 count,记录该值的出现次数,从而减少重复存储。

4. 实战案例:栈的压入、弹出序列

判断一个序列是否是另一个序列的合法弹出顺序。

思路: 模拟入栈过程。遍历压栈数组,依次入栈;每次入栈后检查栈顶是否等于当前期望弹出的元素,若相等则出栈并移动弹出指针。最后检查栈是否为空。

代码实现:

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

5. 实战案例:逆波兰表达式求值

利用栈处理后缀表达式(逆波兰表达式),遇到数字入栈,遇到运算符则弹出两个数字进行计算。

代码实现:

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

6. Stack 模拟实现

了解其本质有助于调试和优化。stack 本质上是对底层容器的包装。

template<class T, class Continer = std::deque<T>>
class stack {
public:
    stack() {}
    void push(const T& val) { _con.push_back(val); }
    void pop() { _con.pop_back(); }
    T& top() { return _con.back(); }
    size_t size() { return _con.size(); }
    bool empty() { return _con.empty(); }
private:
    Continer _con;
};

二、Queue:先进先出

1. Queue 介绍

queue 是 FIFO(先进先出)结构。元素从队尾入队列,从队头出队列。底层容器可以是 deque 或 list,默认为 deque。

Queue 结构示意

2. Queue 常用接口

函数声明接口说明
queue()构造空的队列
empty()检测队列是否为空
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素 val 入队列
pop()将队头元素出队列

3. Queue 模拟实现

由于需要支持头删,vector 不适用(头删效率低),通常选择 list 或 deque。

template<class T, class Continer = std::list<T>>
class queue {
public:
    queue() {}
    void push(const T& val) { _con.push_back(val); }
    void pop() { _con.pop_front(); }
    T& front() { return _con.front(); }
    T& back() { return _con.back(); }
    size_t size() { return _con.size(); }
    bool empty() { return _con.empty(); }
private:
    Continer _con;
};

三、Priority Queue:优先队列

1. Priority Queue 介绍

优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的(默认大堆)。底层容器通常是 vector,通过堆算法维持堆结构。

2. Priority Queue 使用

默认情况下,priority_queue 是大堆。如果需要小堆,可以通过仿函数(Functor)来定制比较逻辑。

函数声明接口说明
priority_queue()构造一个空的优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中最大元素
push(x)在优先级队列中插入元素 x
pop()删除优先级队列中最大元素

3. OJ 实战:数组中的第 K 个最大元素

利用优先队列可以在 O(N log K) 时间内找到第 K 大元素,比完全排序更高效。

思路: 将数组放入优先级队列,弹出 k-1 次后,剩下的栈顶即为第 K 大元素。

代码实现:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int> p(nums.begin(), nums.end());
        while (--k) {
            p.pop();
        }
        return p.top();
    }
};

4. Priority Queue 模拟实现

这里展示了基于 vector 的手动堆实现,包括向上调整(AdjustUp)和向下调整(AdjustDown)。

基础版(大堆):

namespace myPriorityQueue {
template<class T, class Container = std::vector<T>>
class priority_queue {
public:
    void AdjustUp(int child) {
        int parent = (child - 1) / 2;
        while (child > 0) {
            if (_con[child] > _con[parent]) {
                swap(_con[child], _con[parent]);
                child = parent;
                parent = (parent - 1) / 2;
            } else {
                break;
            }
        }
    }

    void AdjustDown(int parent) {
        int child = parent * 2 + 1;
        while (child < _con.size()) {
            if (child + 1 < _con.size() && _con[child + 1] > _con[child]) {
                ++child;
            }
            if (_con[child] > _con[parent]) {
                swap(_con[child], _con[parent]);
                parent = child;
                child = parent * 2 + 1;
            } else {
                break;
            }
        }
    }

    void push(const T& x) {
        _con.push_back(x);
        AdjustUp(_con.size() - 1);
    }

    void pop() {
        swap(_con[0], _con[_con.size() - 1]);
        _con.pop_back();
        AdjustDown(0);
    }

    bool empty() { return _con.empty(); }
    const T& top() { return _con[0]; }
    size_t size() { return _con.size(); }
private:
    Container _con;
};
}

支持仿函数版本(可配置大小堆): 通过引入 Compare 模板参数,可以灵活控制堆的性质。例如传入 greater<T> 即可实现小堆。

namespace myPriorityQueue {
template<class T>
struct less {
    bool operator()(const T& x, const T& y) const {
        return x < y;
    }
};
template<class T>
struct greater {
    bool operator()(const T& x, const T& y) const {
        return x > y;
    }
};

template<class T, class Container = std::vector<T>, class Compare = greater<T>>
class priority_queue {
public:
    priority_queue() = default;

    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last) : _con(first, last) {
        for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {
            AdjustDown(i);
        }
    }

    void AdjustUp(int child) {
        Compare com;
        int parent = (child - 1) / 2;
        while (child > 0) {
            if (com(_con[parent], _con[child])) {
                swap(_con[child], _con[parent]);
                child = parent;
                parent = (parent - 1) / 2;
            } else {
                break;
            }
        }
    }

    void AdjustDown(int parent) {
        Compare com;
        int child = parent * 2 + 1;
        while (child < _con.size()) {
            if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) {
                ++child;
            }
            if (com(_con[parent], _con[child])) {
                swap(_con[child], _con[parent]);
                parent = child;
                child = parent * 2 + 1;
            } else {
                break;
            }
        }
    }

    void push(const T& x) {
        _con.push_back(x);
        AdjustUp(_con.size() - 1);
    }

    void pop() {
        swap(_con[0], _con[_con.size() - 1]);
        _con.pop_back();
        AdjustDown(0);
    }

    bool empty() { return _con.empty(); }
    const T& top() { return _con[0]; }
    size_t size() { return _con.size(); }
private:
    Container _con;
};
}

四、容器适配器与 Deque

1. 什么是适配器

适配器模式将一个类的接口转换成客户希望的另外一个接口。在 STL 中,stack 和 queue 就是典型的容器适配器,它们不直接管理内存,而是包装其他容器。

2. 为什么选择 Deque 作为默认底层容器

deque(双端队列)是一种分段连续的空间数据结构。它在头部和尾部插入删除都是 O(1),且扩容时不需要像 vector 那样搬移大量数据。

  • 对比 Vector:deque 头插效率高,无需搬移元素。
  • 对比 List:deque 空间利用率更高,没有额外的节点指针开销。

虽然 deque 遍历时迭代器较复杂(需检测段边界),但 stack 和 queue 本身不需要遍历,因此 deque 成为了它们的最佳默认搭档。

Deque 结构示意

掌握这些底层原理,能帮助我们在实际开发中更合理地选择数据结构,提升程序性能。

目录

  1. C++ 标准库容器适配器详解
  2. 一、Stack:后进先出
  3. 1. Stack 介绍
  4. 2. Stack 常用接口
  5. 3. 实战案例:最小栈 (Min Stack)
  6. 4. 实战案例:栈的压入、弹出序列
  7. 5. 实战案例:逆波兰表达式求值
  8. 6. Stack 模拟实现
  9. 二、Queue:先进先出
  10. 1. Queue 介绍
  11. 2. Queue 常用接口
  12. 3. Queue 模拟实现
  13. 三、Priority Queue:优先队列
  14. 1. Priority Queue 介绍
  15. 2. Priority Queue 使用
  16. 3. OJ 实战:数组中的第 K 个最大元素
  17. 4. Priority Queue 模拟实现
  18. 四、容器适配器与 Deque
  19. 1. 什么是适配器
  20. 2. 为什么选择 Deque 作为默认底层容器

更多推荐文章

查看全部
  • 昇腾 Ascend C 算子开发:从语法基础到全链路编程实践
  • RAGFlow:融合检索与生成的系统架构及应用解析
  • SpringBoot 配置文件详解:Properties 与 YAML 实战
  • 使用 ComfyUI 实现黏土风格 AI 照片生成教程
  • PX4 开源飞控系统详解:架构、生态与入门指南
  • Function Calling:连接大模型与业务系统的自然语言接口机制
  • 双指针算法实战:唯一雪花、逛画展与丢手绢
  • AVL 树的 C++ 模拟实现及旋转原理
  • 2026 年主流 AI 生成 PPT 工具评测与推荐
  • 鸿蒙金融理财全栈项目:上线运维、用户反馈与持续迭代
  • AI 视频生成模型开源实战:从选型到生产环境部署的避坑指南
  • JavaScript DOM 元素操作:添加、删除、替换与插入详解
  • DeepSeek 隐藏玩法、提示词技巧及本地知识库搭建
  • 前端开发常被低估?聊聊工程化背后的隐形门槛
  • 中国人工智能大模型技术白皮书深度解读:大模型领域入门指南
  • Python 实时爬取东方财富网股票行情:WebSocket 接口解析与低延迟优化
  • Seedance 2.0 双分支扩散变换器架构深度解析与工程实现
  • Mac Intel 芯片安装 Stable Diffusion WebUI 教程
  • C++ 类与对象(上):封装、实例化与 this 指针详解
  • 大模型技术学习路线与核心方法

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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