stack - queue
1.容器适配器
(1) 什么是适配器?
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口
(2) STL标准库中stack和queue的底层结构
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque,比如:
(3) deque简述
deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与 list比较,空间利用率比较高。
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的(分段连续空间组合而成),实际deque类似于一个 动态的二维数组,deque没有所谓容量的概念。其底层结构如下图所示:
(4)deque的迭代器
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器的operator++和operator--两个运算子身上。
构想一下deque应具备的结构:● 能够指出分段连续空间(缓冲区)的位置● 能判断自己是否已经处于其所在缓冲区的边缘,如果前进或后退时就必须跳跃至下一个或上一个缓冲区。
为了能够正确跳跃,deque必须要有掌控中心(map)。
deque的中控器,缓冲区,迭代器的相互关系,如图:
那deque是如何借助其迭代器维护其假想连续的结构呢?
迭代器 start 内的 cur 指针指向缓冲区的第一个元素,迭代器 finish 内的 cur 指向缓冲区的最后元素(的下一个位置)。注意:最后一个缓冲区尚有备用空间,稍后如果有新元素要插入到尾端,可直接拿此备用空间来使用。
template <class T, class Ref, class Ptr, size_t BufSiz>
struct _daque_iterator
{//...//保持与容器的联结T* cur; //此迭代器指向缓冲区中的现行T* first; //此迭代器指向缓冲区的头T* last; //此迭代器指向缓冲区的尾(含备用空间)map_pointer node;//指向控制中心(指针数组)
};
(5) deque的数据结构
deque 除了维护一个指向map的指针外,也维护 start 和 finish 两个迭代器,分别指向第一缓冲区的第一个元素和最后缓冲区的最后一个元素(的下一个位置)。此外,它当然也必须记住目前 map 的大小,因为,一旦 map 所提供的节点不足,就必须重新配置更大的一块 map。
iterator start;iterator finish;map_pointer map;size_type map_size;
(6) deque的缺陷
与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比vector高的。与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。
(7) 为什么选择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的优点,而完美的避开了其缺陷。
2.stack的介绍和应用
cplusplus.com - The C++ Resources Network
(1) stack结构
(2) stack使用
155. 最小栈
思路:辅助栈
实现1:
class MinStack {
public:void push(int val) {_elem.push(val);if(_min.empty() || val <= _min.top()){_min.push(val);}} void pop() {if(_elem.top() == _min.top()){//只有当删除的数据是最小值时,才删_min栈的数据_min.pop();}_elem.pop();} int top() {return _elem.top();} int getMin() {return _min.top();}std::stack<int> _elem;//存所有数据std::stack<int> _min;//只存最小数的栈
};
不需要在构造函数中使用
INT_MAX
来初始化_min
栈。相反,它依赖于在每次push
和pop
操作中检查和维护_min
栈的状态。 通过在每次操作中动态维护最小值,避免了使用INT_MAX
作为初始值的需求
实现2:
class MinStack {
public:MinStack(){_min.push(INT_MAX);}void push(int val) {_elem.push(val);_min.push(min(_min.top(),val));//val值大于栈顶元素也得入数据(栈顶),不然pop数据时最小栈就会失去最小值} void pop() {_elem.pop();_min.pop();} int top() {return _elem.top();} int getMin() {return _min.top();}
private:std::stack<int> _elem;//存储所有元素的栈std::stack<int> _min;//存储最小值的栈
};
INT_MAX
作为_min
栈的初始值是为了简化代码逻辑,确保在任何时候都能快速地获取到栈中的最小值,并且避免在栈为空时调用getMin
方法导致的错误。
JZ31 栈的压入、弹出序列
栈的压入、弹出序列_牛客题霸_牛客网
具体思路:
- 准备一个辅助栈,两个下标分别访问两个序列。
- 辅助栈为空或者栈顶不等于出栈数组当前元素,就持续将入栈数组加入栈中。
- 栈顶等于出栈数组当前元素就出栈。
- 当入栈数组访问完,出栈数组无法依次弹出,就是不匹配的,否则两个序列都访问完就是匹配的。
实现:
class Solution {
public:bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {if(pushV.size() != popV.size())//出栈与入栈数据应一致return false;;stack<int> st;//出入栈stint instack = 0,outstack = 0;while(outstack < popV.size()){// empty要写前面,初次栈里没有数据,无法调用topwhile (st.empty() || st.top() != popV[outstack]) {//先把栈顶与出栈数组元素不同的数据入栈,直到找到相同的if (instack < pushV.size()) {st.push(pushV[instack]);++instack;}else {return false;}}// 这时栈顶数据与出栈数组的元素相同st.pop();++outstack;} return true;}
};
(3) stack模拟实现
默认deque右边是栈顶
#include<deque>
#include<iostream>
using namespace std;
namespace zyt
{
#include<deque>template<class T, class Con = deque<T>>class stack{public:void push(const T& x){_c.push_back(x);}void pop(){_c.pop_back();}T& top(){return _c.back();}const T& top()const{return _c.back();}size_t size()const{return _c.size();}bool empty()const{return _c.empty();}private:Con _c;};
}
3.queue的介绍和应用
queue - C++ Reference
(1) queue简述
1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供 一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。queue不允许有遍历行为。
3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
4. 标准容器类 deque和list 满足了这些要求。默认情况下, 如果没有为queue实例化指定容器类,则使用标准容器 deque (缺省值)
(2) queue的使用
(3) queue没有迭代器
queue所有元素的进出都必须符合“先进先出”的条件,中有queue顶端的元素,才有机会贝被外界取用,queue不提供遍历功能,也不提供迭代器。
(4) queue的模拟实现
namespace zyt
{template<class T, class Con = deque<T>>class queue{public:void push(const T& x){_c.push_back(x);}void pop(){_c.pop_front();}T& back(){return _c.back();}const T& back()const{return _c.back();}T& front(){return _c.front();}const T& front()const{return _c.front();}size_t size()const{return _c.size();}bool empty()const{return _c.empty();}private:Con _c;};
}
4. priority_queue的介绍和使用 (优先级队列)
(1) priority_queue 概述
1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素 中最大的。
2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶 部的元素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue 提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的 顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过 随机访问迭代器访问,并支持以下操作:![]()
5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue 类实例化指定容器类,则使用vector。
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用 算法函数make_heap、push_heap和pop_heap来自动完成此操作。
(2)priority_queue的使用
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中 元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用 priority_queue。注意: 默认情况下priority_queue是大堆 。
1. 默认情况下,priority_queue是大堆。 仿函数控制比较逻辑 (本质是一个类,重载了operator( ),它的对象可以像函数一样使用)
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
#include<iostream>
using namespace std;void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}
2. 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供 > 或者 < 的重载。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载priority_queue<Date> q1;q1.push(Date(2018, 10, 29));q1.push(Date(2018, 10, 28));q1.push(Date(2018, 10, 30));cout << q1.top() << endl;// 如果要创建小堆,需要用户提供>的重载priority_queue<Date, vector<Date>, greater<Date>> q2;q2.push(Date(2018, 10, 29));q2.push(Date(2018, 10, 28));q2.push(Date(2018, 10, 30));cout << q2.top() << endl;
}
(3) OJ中应用
215. 数组中的第K个最大元素
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//默认是建大堆(降序)priority_queue<int> pq(nums.begin(),nums.end());for(int i = 0;i < k - 1 ;i++){pq.pop();//pop的是堆顶数据}return pq.top();}
};
(4) priority_queue的模拟实现
通过对priority_queue的底层结构就是堆,因此此处只需对对进行通用的封装即可。
#pragma once
#include<queue>
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
using namespace std;namespace zyt
{template<class T>struct less{bool operator()(const T& left, const T& right){return left < right;}};template<class T>struct greater{bool operator()(const T& left, const T& right){return left > right;}};template <class T, class Container = vector<T>, class Compare = less<T> >class priority_queue{public:priority_queue():c(){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last):c(first,last){if (c.size() < 2)return;int len = c.size();int parent = (len - 2) / 2; // 最后一个根节点while (parent >= 0){AdjustDown(parent);//自下而上parent--;}}void AdjustUp(size_t child)//向上调整算法{size_t parent = (child - 1) / 2;//父节点while (child > 0 ){if (comp(c[parent] , c[child])){swap(c[parent], c[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void AdjustDown(size_t parent)//向下调整算法{size_t child = 2 * parent + 1;//左孩子while (child < c.size()){if ((child + 1 < c.size()) && comp(c[child], c[child + 1])){++child;}if (comp(c[parent] , c[child])){swap(c[parent], c[child]);parent = child;child = 2 * parent + 1;}else{break;}}}bool empty() const{return c.empty();}size_t size() const{return c.size();}const T& top() const{return c[0];}void push(const T& x){c.push_back(x);AdjustUp(c.size() - 1);}void pop(){if (empty())return;swap(c[0], c[c.size() - 1]);c.pop_back();AdjustDown(0);}private:Container c;Compare comp;};
};
相关文章:

stack - queue
1.容器适配器 (1) 什么是适配器? 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口 (2) STL标准库中stack和queue的底层结构 虽然stack和…...

微软九月补丁星期二发现了 79 个漏洞
微软将在2024 年 9 月补丁星期二修复 79 个漏洞。 微软有证据表明,发布的四个漏洞被野外利用和/或公开披露;所有四个漏洞均已在CISA KEV上列出。微软还在修补四个关键的远程代码执行 (RCE) 漏洞。 不同寻常的是,微软本月尚未修补任何浏览器…...

研1日记12
1. 改19->10 2. 学习数据不平衡问题 1. 欠采样 合并两个样本数据 两种方式 1. 按原分布比例划分。sklearn中train_test_split里,参数stratify含义解析_traintestsplit参数stratify-CSDN博客 3.刘二大人 卷积操作 待看论文: 刘老师指导:…...
Rocky Linux 9安装mysqlclient库报错的解决方法
环境 VMware Rocky Linux 9.4 MySQL 8.0 安装mysqlclient报错 yum install python3-devel pip3 install mysqlclient报错: Downloading http://mirrors.aliyun.com/pypi/packages/37/fb/d9a8f763c84f1e789c027af0ffc7dbf94c9a38db961484f253f0552cbb47/mysqlcli…...

Spring Boot母婴商城:安全、便捷、高效
2 相关技术 2.1 SSM框架介绍 本课题程序开发使用到的框架技术,英文名称缩写是SSM,在JavaWeb开发中使用的流行框架有SSH、SSM、SpringMVC等,作为一个课题程序采用SSH框架也可以,SSM框架也可以,SpringMVC也可以。SSH框架…...
php实现kafka
kafka类: <?phpclass b2c_kafka {public $broker_list;public $topic;public $group_id;protected $producer null;protected $consumer null;protected $receive_wait_time;protected $receive_wait_num;/*** 构造方法* param object app*/public function …...

YOLOv10改进系列,YOLOv10损失函数更换为Powerful-IoU(2024年最新IOU),助力高效涨点
改进前训练结果: 改进后的结果: 摘要 边界框回归(BBR)是目标检测中的核心任务之一,BBR损失函数显著影响其性能。然而,观察到现有基于IoU的损失函数存在不合理的惩罚因子,导致回归过程中锚框扩展,并显著减缓收敛速度。为了解决这个问题,深入分析了锚框扩展的原因。针…...
工具知识 | Linux 常用命令参考手册
目录 文件 查看文件内容 headtailcatnlmore 创建 touchmkdirmktemp 删除 rmrmdir 查找文件 findlocate lspwdwcchattrpastestatgrepsedcdcpmvopensourcetreelnfilesortuniqsplitvim 系统管理 nohupwatchpingwhichshutdownrebootuptimecrontabatunameifconfigwhereischmodlsofc…...
mysql 常用知识点总结
MySQL 是一种广泛使用的关系型数据库管理系统(RDBMS),它基于结构化查询语言(SQL)。了解 MySQL 的语法对数据库管理和操作非常重要。以下是 MySQL 语法的详细完整解释,涵盖基本概念、创建表、查询、修改数据…...
conda常用指令
1、查看conda版本 conda --version 2、更新conda conda update conda 3、查看conda环境信息 conda info 4、查看已有虚拟环境 conda info --envs conda info -e conda env list 5、创建新虚拟环境 conda create --name myenv python3.8 6、激活环境和退出环境 conda…...

前后端分离项目--下载功能
文章目录 不使用代理服务器blobblob构造函数通过FormData对象的getBlob方法创建Blob对象将Blob对象转换成UR 使用代理服务器 前后端分离项目中下载与其他接口的使用不同,一般下载不走node,不通过代理服务器,而是直接在前台发送请求࿰…...

PMP--一模--解题--81-90
文章目录 4.整合管理81、 [单选] 一位先前不活跃的干系人参与程度突然增加,这种意外的参与导致了一些变更请求。项目经理应该做什么? 4.整合管理82、 [单选] 公司的新产品系列将在两个月内发布,95%的项目任务均已完成。但是,管理层…...

计算机网络 --- 【2】计算机网络的组成、功能
目录 一、计算机网络的组成 1.1 从组成部分看 1.2 从工作方式看 1.3 从逻辑功能看 1.4 总结 二、计算机网络的功能 2.1 数据通信 2.2 资源共享编辑 2.3 分布式处理 2.4 提高可靠性 2.5 负载均衡 一、计算机网络的组成 1.1 从组成部分看 我们举例分析计算机网络从…...

『功能项目』切换职业技能面板【49】
我们打开上一篇48切换职业面板的项目, 本章要做的事情是制作第二职业法师技能面板、第三职业面板并且完成切换 双击打开Canvas进入预制体空间 复制三个技能栏面板 重命名 设置第一技能栏 设置第二职业技能栏 设置第三职业技能栏 修改脚本:ChangeProfess…...
寻找排名好的自闭症学校?这些关键因素不可忽视
郑州市如果有一家如星贝育园这样的自闭症公办学校,那无疑将为当地的自闭症儿童及其家庭带来巨大的福音。星贝育园所展现出的专业性、承诺的康复效果保障、以及为特殊儿童提供的全方位支持,都体现了其对自闭症儿童教育康复事业的深刻理解和高度责任感。 …...
Git常用命令(记录)
提交代码 git status 查看状态git add .或者git add xx选择提交全部或者某文件git commit -m “提交信息”git push 创建新分支提交到新的分支 git checkout -b [branch-name] 创建并切换到新分支git add [file-name] 将要上传的文件添加到暂存区git commit -m “commit mes…...

STM32+ESP8266 WiFi连接机智云平台APP远程控制教程
本文档将介绍如何用STM32ESP8266 WiFi模块从零开始连接上机智云,并通过APP进行远程控制。 机智云官网:机智云|智能物联网操作系统 (gizwits.com) 准备:STM32、ESP8266、手机、可上网的WiFi。 1.创建设备 1.1 注册登陆 请自行注册账号并登陆…...
学懂C++(六十):C++ 11、C++ 14、C++ 17、C++ 20新特性大总结(万字详解大全)
一、引言 随着计算机科学与技术的飞速发展,编程语言也在不断进化以满足日益增长的需求。C是一门集高性能和灵活性于一身的编程语言,自1983年诞生以来不断演进,逐渐成为了众多领域的主流编程语言。为了进一步提升开发效率和代码质量࿰…...
杭电1008电梯
提供两种做法,第一种不知道为啥不ac。。。 #include<iostream> using namespace std; //不清楚为什么报错了 int a[10000],x[10000]; int main(){int n;while(cin>>n,n!0){for(int i0;i<n;i){cin>>a[i];if(i0) x[i](65)*a[i]-5;else {if(a[i-…...

【Python小知识 - 2】:在VSCode中切换Python解释器版本
文章目录 在VSCode中切换Python解释器版本 在VSCode中切换Python解释器版本 在VSCode中按下快捷键CtrlShiftP,出现命令框。 输入以下命令: Python: Select Interpreter输入命令回车后即出现不同的Python解释器选项,选择想要切换的Python解释器…...

[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
Linux 内核作为一个多任务操作系统,其进程管理子系统是核心组成部分之一。无论是用户应用的运行、驱动行为的触发,还是系统调度决策,几乎所有操作都离不开进程的创建、调度与销毁。本文将从进程的概念出发,深入探讨 Linux 内核中进…...

如何把 Mac Finder 用得更顺手?——高效文件管理定制指南
系统梳理提升 Mac Finder 体验的实用设置与技巧,助你用更高效的方式管理文件。文末引出进阶选择 Path Finder。 阅读原文请转到:https://jimmysong.io/blog/customize-finder-for-efficiency/ 作为一个用 Mac 多年的用户,我始终觉得 Finder 虽…...

LabVIEW实时系统数据监控与本地存储
基于LabVIEW Real-Time 模块,面向工业自动化、嵌入式测控等场景,提供实时数据采集、监控与本地存储的完整实现路径。通过分层任务调度、TDMS 文件格式应用及跨平台兼容性设计,确保系统在实时性、可靠性与数据管理效率间达到平衡。文中以 Comp…...
6.7本日总结
一、英语 复习默写list10list19,07年第3篇阅读 二、数学 学习线代第一讲,写15讲课后题 三、408 学习计组第二章,写计组习题 四、总结 本周结束线代第一讲和计组第二章,之后学习计网4.4,学完计网4.4之后开操作系…...

win32相关(远程线程和远程线程注入)
远程线程和远程线程注入 CreateRemoteThread函数 作用:创建在另一个进程的虚拟地址空间中运行的线程 HANDLE CreateRemoteThread([in] HANDLE hProcess, // 需要在哪个进程中创建线程[in] LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全…...

QT常用控件(1)
控件是构成QT的基础元素,例如Qwidget也是一个控件,提供了一个‘空’的矩形,我们可以往里面添加内容和处理用户输入,例如:按钮(QpushButton),基础显示控件(Lableÿ…...
软珊瑚成分 CI-A:靶向口腔癌细胞的 “氧化利剑” 与 ERK 密码
在生命科学探索的浩瀚星海中,癌症研究始终是最为耀眼却又充满挑战的领域之一。口腔癌,作为全球范围内日益严峻的公共健康问题,尤其在中南亚、美拉尼西亚以及我国台湾地区,其发病率和死亡率持续攀升,如同隐藏在黑暗中的…...

负载均衡LB》》HAproxy
Ubuntu 22.04 安装HA-proxy 官网 资料 # 更新系统包列表: sudo apt update # 安装 HAproxy sudo apt install haproxy -y # 验证安装 haproxy -v # 如下图配置 Haproxy 在这里插入代码片》》》配置完之后 重启 Haproxy sudo systemctl restart haproxy 补充几…...
Vue中的自定义事件
一、前言 在 Vue 的组件化开发中,组件之间的数据通信是构建复杂应用的关键。而其中最常见、最推荐的方式之一就是通过 自定义事件(Custom Events) 来实现父子组件之间的交互。 本文将带你深入了解: Vue 中事件的基本概念如何在…...

2025年06月05日Github流行趋势
项目名称:onlook 项目地址url:https://github.com/onlook-dev/onlook项目语言:TypeScript历史star数:16165今日star数:1757项目维护者:Kitenite, drfarrell, spartan-vutrannguyen, apps/devin-ai-integrat…...