【C/C++】STL——容器适配器:stack和queue的使用及模拟实现

news2024/11/24 4:35:03

在这里插入图片描述

​👻内容专栏: C/C++编程
🐨本文概括:stack与queue的介绍与使用、模拟实现。
🐼本文作者: 阿四啊
🐸发布时间:2023.10.17

一、stack的介绍与使用

1.1 stack的介绍

以下是stack的文档介绍
在这里插入图片描述

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

1.2 stack的使用

函数说明接口说明
stack()构造空的栈
empty()检测stack是否为空
size()返回stack中元素的个数
top()返回栈顶元素的引用
push()将元素val压入stack中
pop()将stack中尾部的元素弹出
void test_stack()
{
	stack<int> st;
	//元素入栈
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		//打印栈顶元素
		cout << st.top() << " ";
		//出栈
		st.pop();
	}
	cout << endl;
}

下面刷一道leetcode上有关用栈来解决的题目:逆波兰表达式

在这里插入图片描述

基本思路:

1.首先匹配到数字元素就入栈
2.如果匹配到符号,就出栈顶元素进行计算,第一次出栈顶元素表示右操作符,第二次出栈顶元素表示左操作符,运算结果入栈
3.最后栈顶的唯一元素即为运算的结果,返回栈顶元素即可。

代码实现:

class Solution {
public:

    int evalRPN(vector<string>& tokens) {
        //myStack::stack<int,vector<int>> st;
        //myStack::stack<int,list<int>> st;
        myStack::stack<int> st;

        for (auto& str : tokens)
        {
            if (str == "+" ||
                str == "-" ||
                str == "*" ||
                str == "/")
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();

                switch (str[0])
                {
                case '+':
                    st.push(left + right);
                    break;
                case '-':
                    st.push(left - right);
                    break;
                case '*':
                    st.push(left * right);
                    break;
                case '/':
                    st.push(left / right);
                    break;
                }
            }
            else
            {
                st.push(stoi(str));
            }
        }

        return st.top();
    }
};

1.3 stack的模拟实现

我们细心观察文档发现,stack是一个container adaptor,意为容器适配器,它使用的底层容器来存储元素,并提供了一组特定的操作来实现栈的功能。

容器适配器是一种设计模式,它允许使用不同的底层容器来实现相同的功能。在Stack中,可以使用不同类型的容器作为底层实现,例如vector、deque或list。这样可以根据具体的需求选择最适合的底层容器。
在这里插入图片描述
stack.h文件中:

namespace myStack
{
	//Container不管是什么样的底层容器,都可以适配出想要的栈
	//库中的Container缺省参数为deque双端队列
	//template<class T,class Container = deque<T>>
	template<class T, class Container>
	class stack
	{

	public:
		stack()
		{}

		void pop()
		{
			_con.pop_back();
		}

		void push(const T& x)
		{
			_con.push_back(x);
		}
		T& top()
		{
			return _con.back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			return _con.size();
		}

	private:
		
		Container _con;
	};
}

在test.cpp文件中进行测试(以上面一题的代码为例):

//测试stack
#include "stack.h"
class Solution {
public:

    int evalRPN(vector<string>& tokens) {
        //myStack::stack<int,vector<int>> st;
        myStack::stack<int,list<int>> st;

        for (auto& str : tokens)
        {
            if (str == "+" ||
                str == "-" ||
                str == "*" ||
                str == "/")
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();

                switch (str[0])
                {
                case '+':
                    st.push(left + right);
                    break;
                case '-':
                    st.push(left - right);
                    break;
                case '*':
                    st.push(left * right);
                    break;
                case '/':
                    st.push(left / right);
                    break;
                }
            }
            else
            {
                st.push(stoi(str));
            }
        }

        return st.top();
    }
};

int main()
{
    vector<string> str = { "2","1","+","3","*" };
    Solution s;
    cout << s.evalRPN(str) << endl;

	return 0;
}

📌我们用vector和list去适配都能达到想要的结果。在使用库中的list时,我们定义一个list时,并没有实例化给出两个模板参数,这是因为库中有个默认的模板参数Container = deque<T>,至于deque是什么,其名为双端队列,双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象。deque可以说同时具备vector(下标的随机访问)与list(大量中间位置的插入删除)的优点,但是呢deque就好像一个六边形战士,好像什么都会,其实都不厉害,造成了“会而不精”的假象。
后面篇章我们会详细讲解deque.先暂做了解即可。

二、queue的介绍与使用

2.1 queue的介绍

以下为queue的文档介绍
在这里插入图片描述

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

2.2 queue的使用

函数说明接口说明
queue()构造空的队列
empty()检测队列是否为空,是返回true,否则返回false
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素val入队列
pop()将队头元素出队列
void test_queue()
{
	queue<int> q;
	//在队列尾部入队列
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);

	while (!q.empty())
	{
		//返回队头元素
		cout << q.front() << endl;
		//在队列头部出队列
		q.pop();
	}
	cout << endl;
}

2.3 queue的模拟实现

因为queue的接口中存在频繁的头部插入与删除操作,因此使用vector来封装效率太低(STL库中也没有支持对于头部插入删除的操作),故可以借助list来模拟实现queue。
具体如下:
queue.h文件中:

namespace myQueue
{
	//template<class T, class Container = deque<T>>
	template<class T, class Container>
	class queue
	{

	public:
		queue(){}

		T& front()
		{
			return _con.front();
		}
		T& back()
		{
			return _con.back();
		}
		 
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_front();
		}
		bool empty()
		{
			return _con.empty();
		}

		size_t size()
		{
			return _con.size();
		}

	private:
		Container _con;
	};
}

对queue的测试:

#include "queue.h"
//queue的测试
int main()
{
	//使用vetcor会报错,显示pop_front不是其成员,
	//myQueue::queue<int, vector<int>> q;
	//queue<int, vector<int>> q;

	//vector容器不能适配队列,队列标准是先进先出,而vector不支持头插头删
	myQueue::queue<int, list<int>> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);

	while (!q.empty())
	{
		cout << q.front() << " ";
		q.pop();
	}
	cout << endl;
	return 0;
}

同样的,我们在使用库中的queue时,平时也只用传入一个参数进行实例化对象,这是因为库中使用了一个缺省的模板参数Container,底层默认容器为deque.

三、为什么选择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的优点,而完美的避开了其缺陷。

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

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

相关文章

E044-服务漏洞利用及加固-利用redis未授权访问漏洞进行提权

任务实施: E044-服务漏洞利用及加固-利用redis未授权访问漏洞进行提权 任务环境说明&#xff1a; 服务器场景&#xff1a;p9_kali-6&#xff08;用户名&#xff1a;root&#xff1b;密码&#xff1a;toor&#xff09; 服务器场景操作系统&#xff1a;Kali Linux 192.168.3…

【Qt高阶】Linux安装了多个版本的Qt 部署Qt程序,出包【2023.10.17】

简介 linux系统下可执行程序运行时会加载一些动态库so&#xff0c;有一些是Qt的库&#xff0c;Qt的库会加载其他更基础的库。最后出包的时候需要把依赖的包整理到一个文件夹&#xff0c;来制作安装包。近期遇到已经将依赖的so文件拷贝至程序目录下&#xff0c;但还是调系统路径…

AutoCAD 2024:计算机辅助设计(CAD)软件中文版

AutoCAD是一款广受全球设计师和工程师欢迎的计算机辅助设计&#xff08;CAD&#xff09;软件。自1982年首次推出以来&#xff0c;AutoCAD已经经历了多次迭代和改进&#xff0c;不断提升用户在产品设计、建造和工程领域的工作效率。现在&#xff0c;让我们一起探索AutoCAD 2024的…

MySQL中的存储过程

MySQL中的存储过程 概述 由MySQL5.0 版本开始支持存储过程。 如果在实现用户的某些需求时&#xff0c;需要编写一组复杂的SQL语句才能实现的时候&#xff0c;那么我们就可以将这组复杂的SQL语句集提前编写在数据库中&#xff0c;由JDBC调用来执行这组SQL语句。把编写在数据库…

横向移动如何阻止以及防范?

文章目录 背景总结EDR设备监测 (这里以奇安信网神云锁为例) 背景 今天面试&#xff0c;面试官问到了这一个问题&#xff0c;云主机被getshell了&#xff0c;进行了横向移动&#xff0c;如何进行阻止以及防范&#xff1f;当时回答了两个点&#xff1a;通过防火墙出入站策略设置…

HTX 与 Zebec Protocol 展开深度合作,并将以质押者的身份参与 ZBC Staking

自2023年下半年以来&#xff0c;加密市场始终处于低迷的状态&#xff0c;在刚刚结束的9月&#xff0c;加密行业总融资额创下2021年以来的新低&#xff0c;同时在DeFi领域DEX交易额为318.9亿美元&#xff0c;同样创下2021年1月以来的新低。 对于投资者而言&#xff0c;难以从外生…

Apache DolphinScheduler 3.0.0 升级到 3.1.8 教程

安装部署可参考官网 Version 3.1.8/部署指南/伪集群部署(Pseudo-Cluster)https://dolphinscheduler.apache.org/zh-cn/docs/3.1.8/guide/installation/pseudo-cluster 也可以参考我写贴子 DolphinScheduler 3.0安装及使用-CSDN博客DolphinScheduler 3.0版本的安装教程https:…

微信查分,原来这么简单,老师必看攻略

哈喽&#xff0c;亲爱的老师们&#xff01;是不是经常为了查找学生的成绩而烦恼呢&#xff1f;别担心&#xff0c;今天我就来给大家分享一个超级实用的教程——在微信里查分&#xff01;快来一起了解一下吧&#xff01; 首先&#xff0c;我们要清楚成绩查询页面是什么。一般来说…

成都优优聚是专业美团代运营吗?

成都优优聚是一家专注于美团代运营的公司。作为全国知名的美团代运营服务商&#xff0c;成都优优聚拥有丰富的经验和优秀的团队&#xff0c;为各类商家提供全方位的美团代运营解决方案。 美团作为目前国内最大的O2O平台之一&#xff0c;拥有庞大的用户基础和强大的品牌影响力。…

激光雷达标定板精准识别前方障碍物

商用车自动驾驶率先进入商业化运营阶段&#xff0c;这主要是由于商用车对价格的敏感度更低、B端付费意愿更高&#xff0c;以及场景交通复杂程度较低和政策鼓励等因素。在矿区、港口、干线物流、机场、物流园区等细分场景&#xff0c;高级别自动驾驶正在孕育新市场。其中&#x…

【java学习—八】对象类型转换Casting(1)

文章目录 1. 数据类型转换1.1 基本数据类型的 Casting1.2. 对 Java 对象的强制类型转换(造型)2. 对象类型转换举例 1. 数据类型转换 数据类型转换分为基本数据类型转换和对象类型转换。 1.1 基本数据类型的 Casting (1) 自动类型转换&#xff1a;小的数据类型可以自动转换成…

如果你有一次自驾游的机会,你会如何准备?

常常想来一次说走就走的自驾游&#xff0c;但是光是想想就觉得麻烦的事情好多&#xff1a;漫长的公路缺少娱乐方式、偏僻拗口的景点地名难以导航、不熟悉的城市和道路容易违章…… 也因为如此&#xff0c;让我发现了HUAWEI HiCar这个驾驶人的宝藏&#xff01; 用HUAWEI HiCar…

value too long for type character varying报错处理

瀚高数据库 目录 环境 症状 问题原因 解决方案 环境 系统平台&#xff1a;N/A 版本&#xff1a;4.5 症状 使用insert into插入数据时出现报错value too long for type character varying 问题原因 458新增NLS_LENGTH_SEMANTICS参数&#xff0c;默认设置为byte。之前版本默认为…

nordic平台SDK包下载地址

nRF5 SDK downloads - nordicsemi.com

消灭指标二义性!提效30%的指标管理如何炼成?

众所周知&#xff0c;「指标」是企业通过数据分析衡量业绩的重要参数。然而&#xff0c;不同部门、不同渠道往往存在不同的使用场景和术语体系。 举个例子&#xff1a; 这是一家知名的服饰品牌&#xff0c;不同平台渠道归属于不同部门管理。 适逢双11大促&#xff0c;老板说&…

Tmux:终端复用器的基本使用(一)

tmux&#xff08;也称为终端多路复用器&#xff09;是一个强大的终端工具&#xff0c;旨在提高终端用户的工作效率。它允许用户在一个终端窗口内创建多个会话和窗格&#xff0c;从而轻松地在一个屏幕上同时运行多个终端应用程序。tmux 的目标是将多个终端会话和任务组织在一个简…

基于SSM+Vue的毕业生跟踪调查反馈系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

米哈游、复旦发布,具备感知、大脑、行动的大语言模型“智能体”

ChatGPT等大语言模型展示了前所未有的创造能力&#xff0c;但距AGI&#xff08;通用人工智能&#xff09;还有很大的距离&#xff0c;缺少自主决策、记忆存储、规划等拟人化能力。 为了探索大语言模型向AGI演变&#xff0c;进化成超越人类的超级人工智能&#xff0c;米哈游与复…

分治类dp:1017T3

http://cplusoj.com/d/senior/p/SS231017C 感觉可以分治某个区间 [ l , r ] [l,r] [l,r]&#xff0c;且他们都是在下面 k k k 已经选的基础上 然后肯定要枚举最大值&#xff0c;最大值越长越好 Hint 1 Hint 2 f ( l , r , k ) f(l, r, k) f(l,r,k) 可以通过枚举 m i d mid…

深入理解强化学习——强化学习智能体的四要素:模型(Model)

分类目录&#xff1a;《深入理解强化学习》总目录 相关文章&#xff1a; 强化学习智能体的四要素&#xff1a;策略&#xff08;Policy&#xff09; 强化学习智能体的四要素&#xff1a;收益信号&#xff08;Revenue Signal&#xff09; 强化学习智能体的四要素&#xff1a;价…