C++——stack与queue与容器适配器

1.stack和queue的使用

1.1stack的使用

栈这种数据结构我们应该挺熟了,先入后出,只有一个出口(出口靠栈顶近)嘛

stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以操作:
  • empty:判空操作
  • top:获取栈顶元素
  • push:往栈压入元素
  • pop:从栈顶删除元素
  • size:获取栈里有效元素个数
void test()
{stack<int> s;s.push(1);s.push(2);s.push(3);s.push(4);cout << s.size() << endl;while (!s.empty()){cout << s.top() << " ";s.pop();}cout << endl;
}

1.2queue的使用

队列想必也不必我过多介绍,就是排队嘛,先进先出

void test1()
{queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);cout << q.size() << endl;while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;
}

 2.适配器及stack、queue模拟实现

2.1引入

在聊适配器概念之前然我们看看库里面是怎么描述stack和queue的

 不想看英文可以看这 

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

 

队列

 

不想看英文可以看这 

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

2.2适配器的概念

库里面提到stack和queue都是一种容器适配器,那么什么是适配器呢?
可以理解一下电源适配器

标准家庭用电电压为220V,我们设备用电其实并不需要这么高,电源适配器是要让家庭用电的电压降低到适合设备使用的电压

站在这个角度理解的话那么,适配器应该是一种设计模式该种模式是将一个类的接口转换成客户希望的另外一个接口

2.3 STL标准库中stackqueue的底层结构

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

 

2.4stack的模拟实现 

我这实现的是数组栈

namespace xxx
{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;};
}

测试一下

#include<iostream>
#include<queue>
#include<vector>
using namespace std;#include"stack.h"
void test()
{xxx::stack<int, deque<int>> s;s.push(1);s.push(2);s.push(3);s.push(4);cout << s.size() << endl;while (!s.empty()){cout << s.top() << " ";s.pop();}cout << endl;
}
int main()
{test();return 0;
}

 

2.5queue的模拟实现

就是调用其他类的接口,没什么难度我就直接上代码了

namespace xxx
{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;};
}

测一下

void test1()
{xxx::queue<int, deque<int>> q;q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);cout << q.size() << endl;while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;
}

 3.deque

3.1deque引入

我们可以看到上面stack和queue都用deque作为默认的接口,那么deque有什么好呢?

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
库里的介绍
deque(通常发音像“deck”)是双端队列的一个不规则缩写。双端队列是具有动态大小的序列容器,可以在两端(前端或后端)进行扩展或收缩。
特定的库可以以不同的方式实现deques,通常作为某种形式的动态数组。但在任何情况下,它们都允许通过随机访问迭代器直接访问单个元素,并根据需要通过扩展和收缩容器来自动处理存储。因此,它们提供了类似于矢量的功能,但也在序列的开始处,而不仅仅是在序列的结束处,有效地插入和删除元素。但是,与向量不同的是,deque不能保证将其所有元素存储在连续的存储位置:通过将指针偏移到另一个元素来访问deque中的元素会导致未定义的行为。vectors和deque都提供了非常相似的接口,可以用于类似的目的,但在内部都以完全不同的方式工作:虽然vectors使用一个偶尔需要重新分配才能增长的数组,但deque的元素可以分散在不同的存储块中,容器在内部保留必要的信息,以便在恒定时间内直接访问其任何元素,并具有统一的顺序接口(通过迭代器)。因此,deques的内部比向量复杂一点,但这使它们在某些情况下能够更有效地生长,尤其是在非常长的序列中,重新定位变得更加昂贵。对于涉及在除开头或结尾以外的位置频繁插入或删除元素的操作,与列表和前向列表相比,deques的性能更差,迭代器和引用的一致性也更低。

3.2deque的缺陷

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

3.3为什么选择deque作为stackqueue的底层默认容器

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的优点,而完美的避开了其缺陷。

4.优先级队列 priority_queue

4.1介绍

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

4.2使用

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:
默认情况下priority_queue是大堆。
void test2()
{priority_queue<int> pq;pq.push(1);pq.push(2);pq.push(3);pq.push(4);pq.push(5);pq.push(6);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}

4.3 实现

    template <class T, class Container = vector<T>>class priority_queue{public:void adjust_up(int child){int parent = (child - 1) / 2;while (child > 0){if (c[child] > c[parent]){swap(c[child], c[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjust_down(int parent){int child = parent * 2 + 1;while (child < c.size()){if (child + 1 < c.size() && c[child + 1] > c[child]){++child;}if (c[child] > c[parent]){swap(c[child], c[parent]);parent = child;child = parent * 2 + 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);adjust_up(c.size()-1);}void pop(){swap(c[0], c[c.size() - 1]);c.pop_back();adjust_down(0);}private:Container c;};

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

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

相关文章

专业知识库:中小型企业必备的高效工具

在如今这个信息爆炸的时代&#xff0c;知识管理已经成为了企业运营的重要环节。特别是对于中小型企业来说&#xff0c;如何有效地管理公司内部的知识&#xff0c;提高工作效率&#xff0c;已经成为了一个亟待解决的问题。在这篇文章中&#xff0c;我将向大家介绍一种能够帮助企…

Python轴承故障诊断入门教学

目录 往期精彩内容&#xff1a; 1 工作室实验平台介绍 2 轴承故障诊断教程—数据集 3 轴承故障诊断教程—算法模型 3.1 振动分析方法 3.2 频域特征提取 3.3 时域特征提取 3.4 模型基础的机器学习方法 3.5 深度学习方法 3.6 时频域融合方法 3.7 信号重构方法 3.8 基…

Linux-----文本三剑客补充~

一、模糊匹配 模糊匹配用 ~ 表示包含&#xff0c;!~表示不包含 1、匹配含有root的列 [rootlocalhost ~]#awk -F: /root/ /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [rootlocalhost ~]#awk -F: $1~ /root/ /etc/passw…

知名开发工具RubyMine全新发布v2023.3——支持AI Assistant

RubyMine 是一个为Ruby 和 Rails开发者准备的 IDE&#xff0c;其带有所有开发者必须的功能&#xff0c;并将之紧密集成于便捷的开发环境中。 RubyMine v2023.3正式版下载 新版本改进AI Assistant支持、Rails应用程序和引擎的自定义路径、对Rails 7.1严格locals的代码洞察、RB…

人胰岛素样生长因子-1 ELISA试剂盒IGF-1 (human), ELISA kit

高灵敏ELISA试剂盒&#xff0c;4小时内可得结果&#xff0c;最低可检测34.2 pg/ml的IGF-1 胰岛素样生长因子-1&#xff08;IGF-1&#xff09;是一种多肽激素&#xff0c;在结构上与胰岛素相似。它参与调节中枢和周围神经系统的神经元生长和发育。IGF-1是一种有效的神经元凋亡抑…

【Zookeeper】what is Zookeeper?

官网地址&#xff1a;https://zookeeper.apache.org/https://zookeeper.apache.org/ 以下来自官网的介绍 ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. A…

机试复习-3

前言&#xff1a;前面耽误太多时间&#xff0c;2月份是代码月&#xff0c;一定抓紧赶上&#xff0c;每天至少两道题 day1 2024.2.6 1.排序开启&#xff1a; 1.机试考试&#xff1a;排序应用考察 c的qsort c的sort 作用&#xff1a;对数组&#xff0c;vector排序&#…

c#读取csv文件中的某一列的数据

chat8 (chat779.com) 上面试GPT-3.5,很好的浏览网站&#xff0c;输入问题&#xff0c;可得到答案。 问题1&#xff1a;c#如何在csv中读取某一列数据 解答方案&#xff1a;在 C#中&#xff0c;你可以使用File.ReadAllLines来读取CSV中的所有行&#xff0c;然后逐行解析每一行…

flask+vue+python跨区通勤人员健康体检预约管理系统

跨区通勤人员健康管理系统设计的目的是为用户提供体检项目等功能。 与其它应用程序相比&#xff0c;跨区通勤人员健康的设计主要面向于跨区通勤人员&#xff0c;旨在为管理员和用户提供一个跨区通勤人员健康管理系统。用户可以通过系统及时查看体检预约等。 跨区通勤人员健康管…

Linux 分析指定JAVA服务进程所占内存CPU详情

1、获取服务进程PID [rootVM-32-26-centos ~]# service be3Service status Application is running as root (UID 0). This is considered insecure. Running [25383]2、获取进程占用详情 [rootVM-32-26-centos ~]# cat /proc/25383/status Name: java Umask: 0022 State: S…

Linux 文件比较工具

在Linux系统中&#xff0c;文件比较是一种常见的任务&#xff0c;用于比较两个文件之间的差异。文件比较可以帮助我们找出两个文件的不同之处&#xff0c;或者确定它们是否完全相同。在Linux中&#xff0c;有多种方法可以进行文件比较。 1. diff 在Linux中&#xff0c;diff命…

啤酒:精酿啤酒与冷盘的清新搭配

在夏日的傍晚&#xff0c;当太阳逐渐西沉&#xff0c;微风轻轻拂过&#xff0c;与亲朋好友围坐在一起&#xff0c;享受Fendi Club啤酒与冷盘的清新搭配&#xff0c;无疑是一种生活的享受。这两者的结合&#xff0c;不仅为味蕾带来了全新的体验&#xff0c;更为我们带来了片刻的…

24、数据结构/排序相关练习20240206

一、现有无序序列数组为{23,24,12,5,33,5,34,7}&#xff0c;请使用以下排序实现编程。 函数1&#xff1a;请使用冒泡排序实现升序排序 函数2&#xff1a;请使用简单选择排序实现升序排序 函数3&#xff1a;请使用快速排序实现升序排序 函数4&#xff1a;请使用插入排序实现…

记录 | linux下切换python版本

查看系统中存在的 python 版本 ls /usr/bin/python* 查看系统默认的 python 版本 python --version

《Git 简易速速上手小册》第3章:分支管理(2024 最新版)

文章目录 3.1 创建与合并分支3.1.1 基础知识讲解3.1.2 重点案例&#xff1a;为 Python 项目添加新功能3.1.3 拓展案例 1&#xff1a;使用 Pull Requests (PRs) 在团队中合作3.1.4 拓展案例 2&#xff1a;解决合并冲突 3.2 分支策略的最佳实践3.2.1 基础知识讲解3.2.2 重点案例&…

git合入的parents和child

最近在管理代码&#xff0c;有2的权限&#xff0c;看到一些以前1看不到的东西。 有时候会遇到多个人基于同一节点提交代码&#xff0c;那就要选择先合入和后合入&#xff0c;如果这多人修改到同一个文件同一个地方&#xff0c;就可能产生冲突&#xff0c;一般要避免这种情况出…

Python进阶----在线翻译器(Python3的百度翻译爬虫)

目录 一、此处需要安装第三方库requests: 二、抓包分析及编写Python代码 1、打开百度翻译的官网进行抓包分析。 2、编写请求模块 3、输出我们想要的消息 三、所有代码如下&#xff1a; 一、此处需要安装第三方库requests: 在Pycharm平台终端或者命令提示符窗口中输入以下代…

可解释性AI(XAI)的主要实现方法和研究方向

文章目录 每日一句正能量前言主要实现方法可解释模型模型可解释技术 未来研究方向后记 每日一句正能量 当你还不能对自己说今天学到了什么东西时&#xff0c;你就不要去睡觉。 前言 随着人工智能的迅速发展&#xff0c;越来越多的决策和任务交给了AI系统来完成。然而&#xff…

必看!嵌入式基于UART的通信协议-RS232、RS485协议解析

这两种都是串口通讯的变种&#xff0c;为了提升串口通信的距离和稳定性。通常来说&#xff0c;正常的串口通信使用的是TTL电平&#xff0c;即高电平为2.4-5V&#xff0c;低电平为0-0.4V。高低电平之间的范围很小&#xff0c;如果有静电或者其他外界的干扰&#xff0c;很快会将低…

BT656视频传输标准

前言 凡是做模拟信号采集的&#xff0c;很少不涉及BT.656标准的&#xff0c;因为常见的模拟视频信号采集芯片都支持输出BT.656的数字信号&#xff0c;那么&#xff0c;BT.656到底是何种格式呢&#xff1f; 本文将主要介绍 标准的 8bit BT656&#xff08;4:2:2&#xff09;YCbC…