深入刨析C++ stl::stack 、stl::queue 及 priority_queue

深入刨析C++ stl::stack 、stl::queue 及 priority_queue

                        欢迎来到干货小仓库!!!

“Stack Overflow 教会我: 提问不可耻,放弃搜索才是”


1.stack的介绍和使用

1.1stack的介绍

1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:empty:判空操作back:获取尾部元素操作push_back:尾部插入元素操作pop_back:尾部删除元素操作4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

遵循 “先进后出” 原则。

                                ​​​​​​​        

1.2stack的使用

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

2.queue的介绍和使用

2.1queue的介绍

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:empty:检测队列是否为空size:返回队列中有效元素的个数front:返回队头元素的引用back:返回队尾元素的引用push_back:在队列尾部入队列pop_front:在队列头部出队列4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

遵循"先进先出"原则。

2.2queue的使用

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

3.priority_queue的介绍和使用

3.1介绍

1.底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:empty():检测容器是否为空size():返回容器中有效元素个数top():返回容器中第一个元素的引用push():在容器插入元素pop():删除容器元素2.标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。

3.2使用

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构。

因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。

函数声明接口说明
priority_queue()构造一个空的优先级队列
priority_queue(InputIterator first,InputIterator last)迭代器初始化
empty()检测优先级队列是否为空,是返回true,否则返回false
top()
返回优先级队列中最大(最小元素),即堆顶元素
push(const T& val)在优先级队列中插入val元素
pop()
删除优先级队列中最大(最小)元素,即堆顶元素

4.容器适配器

通过字面理解,所谓的 适配器  就相当于我们在给我们手机充电的时候,电压是220V,难道往我们手机直接充电就是 220W的电压,很显然这不符合我们所理解的常识,我们的充电器的插头就充当了这个角色("适配器").

适配器是一种设计模式(设计模式是一套反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另一个接口。

template<class T,class Containter = deque<T>> class stack { //...... private: Containter _con; };

直观的理解就是 一个模板参数,这个模板参数是一个容器(可以是vector、list.....),作为成员变量的类型,根据使用者传的类型,作为成员变量的类型。

为什么stack和queue在STL中并没有将其划分在容器的队列,而是将其称为 "容器适配器"?



这是因为stack 和 queue 只是对其他容器的接口进行了包装。STL中stack 和queue的 默认适配器使用的是 deque。(下面有解析).

5.双端队列(deque)

5.1deque的原理介绍

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

注意:deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。底层原理:

优缺点:

deque缺陷:①中间插入和删除.②频繁的访问(operator[]).双端队列的迭代器底层实现

5.2为什么选择deque作为stack和queue的底层默认容器?

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:



1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。

2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。



结合了deque的优点,而完美的避开了其缺陷。

6.Stack的模拟实现

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

7.queue的模拟实现

template<class T, class Container = deque<T>> class queue { public: void push(const T& x) { _con.push_back(x); } void pop() { _con.pop_front(); //禁止vector当适配器,代价太大 //_con.erase(_con.begin()); } T& front() { return _con.front(); } T& back() { return _con.back(); } size_t size() { return _con.size(); } bool empty() { return _con.empty(); } private: Container _con; };

8.仿函数

仿函数就是一个模板参数,根据这个模板参数可以实现控制数据的排序是按升序还是降序。

这个模板参数封装成了类,重载了operator(),通过调用类模板参数的类的运算符重载(operator > 和operator <)来实现自定义类型的比较。

示例:

特殊情况:仿函数需要自己实现

例如:

9.priority_queue模拟实现

template<class T, class Container = vector<T>, class Compare = less<T>> class priority_queue { Compare com; //向下调整 void AdjustDown(int parent) { int child = parent * 2 + 1; while (child < _con.size()) { //if (child + 1 < _con.size() && _con[child] < _con[child + 1]) 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 AdjustUp(int child) { Compare com; int parent = (child - 1) / 2; while (child > 0) { //if (_con[child] >_con[parent]) if (com(_con[parent], _con[child])) { swap(_con[child], _con[parent]); child = parent; parent = (child - 1) / 2; } else break; } } public: priority_queue() { } //迭代器初始化 template<class Inputiterator> priority_queue(Inputiterator first, Inputiterator last) { while (first != last) { _con.push_back(*first); ++first; } //建堆 for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) { AdjustDown(i); } } 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); } const T& top() { return _con[0]; } size_t size() { return _con.size(); } bool empty() { return _con.empty(); } private: Container _con; };


觉得不错的,记得点赞+收藏!!!

Read more

Python——Windows11环境安装配置Python 3.12.5

Python——Windows11环境安装配置Python 3.12.5

目录 * 一、下载Python * 二、下载Python步骤 * 三、安装Python * 四、验证Python * 4.1、验证Python环境 * 4.2、验证pip * 4.3、更新pip * 4.4、pip镜像源切换(永久切换,全局生效,清华镜像源和阿里云镜像源二选一即可) * 4.4.1、清华镜像源 * 4.4.2、阿里云镜像源 * 4.5、安装依赖包(检验是否成功) * 五、配置环境变量(可选) 一、下载Python 或者百度网盘下载 链接: https://pan.baidu.com/s/1Rc8g1mZrfDtOexev2JK7NA?pwd=

By Ne0inhk

2026最新保姆级教程:Windows 下使用 uv 从零配置 Python (OpenCV) 环境指南

Windows 下使用 uv 从零配置 Python (OpenCV) 环境指南 本文档适用于在一台全新的 Windows 电脑上,使用 uv 快速配置vscode + Python 3.10 开发环境,并安装 OpenCV 库。同时包含关于 uv 的进阶说明。 B站配套视频 2026最新:使用uv管理python&opencv 🟢 第一步:安装 uv 包管理器 既然电脑上什么都没有,我们需要先安装这个核心工具。 1. 按下 Win + R 键,输入 powershell,按回车打开终端。 2. 复制并粘贴以下命令,按回车运行(三选一): * 或者进如 uv 下载链接 找到

By Ne0inhk
流处理、实时分析与RAG驱动的Python ETL框架:构建智能数据管道(上)

流处理、实时分析与RAG驱动的Python ETL框架:构建智能数据管道(上)

第一章:引言:数据处理的范式革命与Python的崛起 1.1 数据处理范式的演进:从批处理到实时智能 * 批处理时代(ETL 1.0):T+1模式,Hadoop/MapReduce主导,数据价值滞后,决策延迟显著。Python在脚本化、数据清洗环节崭露头角(Pandas, NumPy)。 * 流处理兴起(ETL 2.0):Kafka, Storm, Spark Streaming等推动“准实时”处理,满足监控、告警等场景。Python通过PySpark、Faust等库开始涉足流处理。 * 实时分析时代(ETL 3.0):Flink, Kafka Streams等实现毫秒级延迟,支持复杂事件处理(CEP)、实时仪表盘、在线机器学习。Python生态(Apache Beam Python

By Ne0inhk
千面之法: 释放 C++ 多态的灵活威力

千面之法: 释放 C++ 多态的灵活威力

目录 1:多态的概念 1.1:概念 2.多态的定义与实现 2.1:多态的构成条件 2.2:虚函数 2.3:虚函数的重写 2.3.1:虚函数重写的两个例外 2.3.1.1:协变(基类与派生类函数的返回值不同,基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类对象的指针或引用时) 2.3.1.2:析构函数的重写 2.4:C++11 override和final 2.4.1:final关键字 2.4.2:override关键字 2.5:重载、

By Ne0inhk