C++——stack和queue

目录

stack的介绍和使用

stack的使用

queue的介绍和使用

queue的使用

容器适配器

deque的介绍

deque的缺陷

priority_queue的介绍和使用

priority_queue的使用

仿函数

反向迭代器


stack的介绍和使用

在原来的数据结构中已经介绍过什么是栈了,再来回顾一下:
  1. stack是一种容器适配器(关于什么是容器适配器之后下面会讲到),专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与删除操作。
  2. stack是作为容器适配器被实现的,容器适配器是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类。
  4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque(这个后面也会讲)。

stack的使用

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

这些接口的使用都非常简单,也不再过多说明。


queue的介绍和使用

  1. 队列也是一种容器适配器,专门用于在FIFO上下文(first in first out 先进先出)中操作,其中从容器一端插入元素,另一端删除元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。

  4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

queue的使用

函数声明接口说明
queue();
构造空的队列
bool empty() const;
检测队列是否为空

size_t size() const;

返回队列中有效元素的个数
value_type& front();
返回队头元素的引用
value_type& back();
返回队尾元素的引用
void push(const value_type& val);
在队尾将元素val入队列
void pop();
将队头元素出队列


容器适配器

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

        虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque。


deque的介绍

        deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口不仅可以在头尾两端进行插入和删除操作,而且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
        deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:
        从网上找了一张图片,双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂。
        图中的cur指向当前数据,first和last表示buffer开始和结束,node反向指向中控器,方便找下一个buffer。

deque的缺陷

        与vector相比,deque的优势是:头插和头删时,不需要搬移元素,效率高,而且在扩容时,也不需要搬移大量的元素,因此其效率比vector高的。
        与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
        但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下;中间插入删除效率不高。而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。
 
结论:
  1. 头尾插入删除非常适合,相比于vector和list,更适合做stack和queue的默认适配器。
  2. 中间插入删除多,使用list。
  3. 随机访问多,使用vector。

priority_queue的介绍和使用

priority_queue是优先级队列

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问。
  5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。 
  6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

priority_queue的使用

        优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的时候,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。
函数声明接口说明
priority_queue();
构造一个空的优先级队列
bool empty() const;
检测优先级队列是否为空
const value_type& top() const;
返回优先级队列中堆顶元素
void push(const value_type& x)在优先级队列中插入x
void pop()删除优先级队列中的堆顶元素
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type>>
class priority_queue; // 第一个模板参数是队列中的元素类型,第二个是用什么容器,第三个决定是大堆还是小堆

仿函数

        仿函数,有点地方也叫做函数对象,这其实就是一个类,这个类重载了一个operator()。

class less
{operator()(const int& l, const int& r){public:return l < r;}
};int main()
{less fun; // 这里的fun并不是一个函数,而是一个类对象,可以像函数一样使用fun(1, 2); // 它的本质是在调用fun.opeartor()(1, 2),所以这里返回值应该是1return 0;
}
// 所以这样好用的不该拘泥于整型,可以改成模板
template<class T>
class less
{operator()(const T& l, const T& r) const{public:return l < r;}
};// 既然有小于,就有大于
template<class T>
class greater
{operator()(const T& l, const T& r) const{public:return l > r;}
};int main()
{less<int> fun1;fun1(1, 2);greater<int> func2;func2(2, 1);return 0;
}
int main()
{// 使用优先级队列,显示传第三个模板参数就是这样的,默然就是大堆,想要建小堆就改成greater<int>priority_queue<int, vector<int>, less<int>> pq;// 当然要注意的是,这里传入的是类型,相比于sort函数,传入的是对象,这就可以使用匿名对象vector<int> v(5, 5);sort(v.begin(), v.end(), less<int>()); // sort默认排的升序,想要降序就传入greater<int>()return 0;
}

反向迭代器

        前面讲到了正向迭代器的使用,那也要说一下反向迭代器的实现,反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++运算将访问前一个元素,而 - -运算则访问下一个元素。

// 复用,迭代器适配器
template<class Iterator, class Ref, class Ptr>
struct __reverse_iterator
{iterator _cur; // 使用正向迭代器构造一个反向迭代器typedef __reverse_iterator<Iterator> RIterator;__reverse_iterator(Iterator it):_cur(it){}RIterator operator++() // 注意这里只有前置++和--,后置是差不多的{--_cur;return *this;}RIterator operator--(){++ _cur;return *this;}Ref operator*() // 返回引用类型{auto tmp = _cur;--tmp;return *tmp;// 这里这么写的原因是,begin返回第一个位置的迭代器,end返回最后一个位置的迭代器// rbegin返回最后一个位置的迭代器,rend返回第一个位置前一个的迭代器// 写的时候可以复用begin和end,rbegin返回end位置,rend返回begin位置// 这里的cur就是构造的反向迭代器,先--后就是正确的位置}Ptr opeartor->() // 返回指针{// return _cur.operator->();return &(operator*());}bool operator!=(const RIterator& it){return _cur != it._cur;}
};

        这样可以适配生成某些容器的反向迭代器,有些容器比较特殊,所以不支持,比如单链表forward_list,它只支持++并不支持- -;unordered_map和unordered_set也是不支持的,这就要到后面再说了。

        从某些功能的角度分析,迭代器也可以分成几类:

  • forward_iterator,它只支持++,因为它是单向的。容器有:unordered_map,unordered_set,forward_list。
  • bidirectional_iterator,它支持++和- -,它是双向的。容器有:list,map,set。
  • random_access_iterator,它不仅支持++和- -,还支持+和-,他是随机的。容器有:deque,vector。

        这里的迭代器从下到上是一种继承关系,关于什么是继承后面也会讲。简单理解一下,随机迭代器也是双向的,拿sort函数和reverse函数举例,sort函数接口的参数类型就是随机迭代器的,reverse函数接口就是双向的,但是可以用随机类型的容器调用reverse这个函数;相对的,双向类型的容器就不能调用sort这个函数。vector可以调用reverse函数,list不能调用sort函数(algorithm库中的)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/164538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频监控平台EasyCVR+智能分析网关+物联网,联合打造智能环卫监控系统

一、背景介绍 城市作为人们生活的载体&#xff0c;有着有无数楼宇和四通八达的街道&#xff0c;这些建筑的整洁与卫生的背后&#xff0c;是无数环卫工作人员的努力。环卫工人通过清理垃圾、打扫街道、清洗公共设施等工作&#xff0c;保持城市的整洁和卫生&#xff0c;防止垃圾…

【机器学习 | 白噪声检验】检验模型学习成果 检验平稳性最佳实践,确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

C++ Day09 容器

C-STL01- 容器 引入 我们想存储多个学员的信息 , 现在学员数量不定 通过以前学习的知识 , 我们可以创建一个数组存储学员的信息 但是这个数组大小是多少呢 ? 过大会导致空间浪费 , 小了又需要扩容 对其中的数据进行操作也较为复杂 每次删除数据后还要对其进行回收等操作…

cookie的跨站策略 跨站和跨域

借鉴&#xff1a;Cookie Samesite简析 - 知乎 (zhihu.com) 1、跨站指 协议、域名、端口号都必须一致 2、跨站 顶级域名二级域名 相同就行。cookie遵循的是跨站策略

PowerDesigner异构数据库转换

主要流程:sql->pdm->cdm->other pdm->sql 1.根据sql生成pdm 2.根据pdm生成cdm 3.生成其他类型数据库pdm

【Java】认识String类

文章目录 一、String类的重要性二、String类中的常用方法1.字符串构造2.String对象的比较3.字符串查找4.转换5.字符串替换6.字符串拆分7.字符串截取8.其他操作方法9.字符串的不可变性10.字符串修改 三、StringBuilder和StringBuffer 一、String类的重要性 在C语言中已经涉及到…

C语言第二十五弹--打印菱形

C语言打印菱形 思路&#xff1a;想要打印一个菱形&#xff0c;可以分为上下两部分&#xff0c;通过观察可以发现上半部分星号的规律是 1 3 5 7故理解为 2对应行数 1 &#xff0c;空格是4 3 2 1故理解为 行数-对应行数-1。 上半部分代码如下 for (int i 0;i < line;i){//上…

Vivado Modelsim联合进行UVM仿真指南

打开Vivado&#xff0c;打开对应工程&#xff0c;点击左侧Flow Navigator-->PROJECT MANAGER-->Settings&#xff0c;打开设置面板。点击Project Settings-->Simulation选项卡&#xff0c;如下图所示。 将Target simulator设为Modelsim Simulator。 在下方的Compil…

OpenGL 绘制圆形平面(Qt)

文章目录 一、简介二、代码实现三、实现效果一、简介 这里使用一种简单的思路来生成一个圆形平面: 首先,我们需要生成一个单位圆,半径为1,法向量为(0, 0, 1),这一步我们可以使用一些函数生成圆形点集。之后,指定面片的索引生成一个圆形平面。当然这里为了后续管理起来方便…

Py之PyMuPDF:PyMuPDF的简介、安装、使用方法之详细攻略

Py之PyMuPDF&#xff1a;PyMuPDF的简介、安装、使用方法之详细攻略 目录 PyMuPDF的简介 PyMuPDF的安装 PyMuPDF的使用方法 1、基础用法 PyMuPDF的简介 PyMuPDF是一个高性能的Python库&#xff0c;用于PDF(和其他)文档的数据提取&#xff0c;分析&#xff0c;转换和操作。 …

Matrix

Matrix 如下是四种变换对应的控制参数&#xff1a; Rect 常用的一个“绘画相关的工具类”&#xff0c;常用来描述长方形/正方形&#xff0c;他只有4个属性&#xff1a; public int left; public int top; public int right; public int bottom; 这4个属性描述着这一个“方块…

基于JavaWeb+SSM+Vue校园水电费管理小程序系统的设计和实现

基于JavaWebSSMVue校园水电费管理小程序系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 摘 要 III Abstract 1 1 系统概述 2 1.1 概述 2 1.2课题意义 3 1.3 主要内容 3…

使用【画图】软件修改图片像素、比例和大小

打开电脑画图软件&#xff0c;点击开始 windows附件 画图 在画图软件里选择需要调整的照片&#xff0c;点击文件 打开 在弹出窗口中选择照片后点击打开 照片在画图软件中打开后&#xff0c;对照片进行调整。按图中顺序进行 确定后照片会根据设定的值自动调整 保存…

Codeforces Round 745 (Div. 2)(C:前缀和+滑动窗口,E:位运算加分块)

Dashboard - Codeforces Round 745 (Div. 2) - Codeforces A&#xff1a; 答案就是2n!/2, 对于当前满足有k个合法下标的排列&#xff0c;就是一个n-k个不合法的下标的排列&#xff0c; 所以每一个合法排列都相反的存在一个 对称性 #include<bits/stdc.h> using nam…

【Redisson】基于自定义注解的Redisson分布式锁实现

前言 在项目中&#xff0c;经常需要使用Redisson分布式锁来保证并发操作的安全性。在未引入基于注解的分布式锁之前&#xff0c;我们需要手动编写获取锁、判断锁、释放锁的逻辑&#xff0c;导致代码重复且冗长。为了简化这一过程&#xff0c;我们引入了基于注解的分布式锁&…

JS获取时间戳的五种方法

一、JavasCRIPT时间转时间戳 JavaScript获得时间戳的方法有五种&#xff0c;后四种都是通过实例化时间对象new Date() 来进一步获取当前的时间戳&#xff0c;JavaScript处理时间主要使用时间对象Date。 方法一&#xff1a;Date.now() Date.now()可以获得当前的时间戳&#x…

思维模型 等待效应

本系列文章 主要是 分享 思维模型 &#xff0c;涉及各个领域&#xff0c;重在提升认知。越是等待&#xff0c;越是焦虑。 1 等待效应的应用 1.1 等待效应在管理中的应用 西南航空公司是一家美国的航空公司&#xff0c;它在管理中运用了等待效应。西南航空公司鼓励员工在工作中…

快速学会使用Python3.12的新特性

一、 PEP 695: 类型形参语法的革新 PEP 695 在 Python 3.12 中引入了一种新颖且更为清晰的方式来定义泛型类和函数&#xff0c;旨在提升类型参数的明确性和简洁性。这个提案不仅改善了类型系统的可读性&#xff0c;还增强了其功能性。以下是这些变化的详细概述&#xff1a; 1…

(四)C语言之符号常量概述

&#xff08;四&#xff09;C语言之符号常量概述 一、符号常量概述 一、符号常量概述 在程序中使用像300,20等这样的等类似的“幻数”不是一个好的习惯&#xff0c;它们无法向阅读该程序的人提供更多有用的信息&#xff0c;从而使得修改程序变得困难。处理这种幻数的一种方法是…

unreal 指定windows SDK

路径 &#xff1a; “C:\Users\Administrator\AppData\Roaming\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml” 在Configuration中添加 <WindowsPlatform><WindowsSdkVersion>10.0.20348.0</WindowsSdkVersion></WindowsPlatform>示例&…