【C++杂货铺】详解 stack 和 queue


🌈前言🌈

        欢迎收看本期【C++杂货铺】,本期内容将讲解C++STL中stack和queue的内容,其中包含了stack , queue,priority_queue是什么,怎么使用以及模拟实现这些容器。

        此外,还将将讲解设计模式中的适配器模式,以及STL中stack,queue的底层deque。

📁 stack 介绍和使用

 📂 介绍

        stack是一种容器适配器,专门用于具有先进后出的上下文环境,只能从容器的一端进行元素的插入和提取操作。

        stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层,元素特定容器的尾部被压入和弹出。

        stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持一下操作:

        ● empty : 判空操作。

        ● back:获取尾部元素操作。

        ● push_back:尾部插入元素操作。

        ● pop_back:尾部删除元素操作。

        标准容器vector,deque,list均符合这些需求,默认情况下,如果没有stack指定特定的底层容器,默认情况下使用deque。

📂 使用

stack - C++ Reference (cplusplus.com)

#include <iostream>
#include <stack>

using namespace std;

int main()
{
    stack<int> st;

    st.push(1);
    st.push(2);
    st.push(3);

    while(!st.empty())
    {
        cout<<st.top()<<" ";
        st.pop();    
    }
    cout<<endl;
}

 📂 模拟实现

#include<deque>
namespace exercise
{
 template<class T, class Con = deque<T>>
 class stack
 {
 public:
     stack() {}
     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;
 };
}

📁 queue 介绍和使用

 📂 介绍

        队列也是一种容器适配器,专门用于先进先出的操作,其中从容器一端插入元素,另一端提取元素。

        队列作为容器适配器实现,容器适配器将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素,元素从队尾入队列,从队头出队列。

        底层容器可以是变化尊模板容器类模板之一,也可以是其他专门设计的容器类,该底层容器应该支持一下操作:

        ● empty : 检测队列是否为空。

        ● size : 返回队列中有效元素的个数。

        ● front : 返回队头元素的引用。

        ● back:返回队尾元素的引用。

        ● push_back:在队列尾部入队列。

        ● pop_back:在队列头部出队列。

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

 📂 使用

queue - C++ Reference (cplusplus.com)

#include <iostream>
#include <queue>

using namespace std;

int main()
{
    queue<int> q;

    q.push(1);
    q.push(2);
    q.push(3);

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

 📂 模拟实现

#include <deque>
#include <list>
namespace exercise
{
 template<class T, class Con = deque<T>>
 //template<class T, class Con = list<T>>
 class queue
 {
 public:
     queue() {}
     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;
 };
}

📁 priority_queue 介绍和使用

 📂 介绍

        优先队列也是一种容器适配器,根据严格的若排序标准,它的第一个元素总是它所包含元中最大的。

        本质上优先队列就是堆,在堆中可以随时插入元素,并且只能检索最大/小元素(优先队列中位于顶部的元素)。

        容器适配器将特定容器类封装为底层容器类,priority_queue提供一组特定的成员函数来访问其元素。元素从特定容器的尾部弹出,其称为优先队列的顶部。

        底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类,容器应该是可以通过随机访问迭代器访问,支持以下操作:

        ● empty : 检测容器是否为空。

        ● size : 返回容器中有效元素的个数。

        ● front : 返回容器第一个元素的引用。

        ● push_back:在容器尾部插入元素。

        ● pop_back:删除容器尾部元素。

        标准容器类vector和deque满足这些需求。默认情况下,使用vector作为底层容器类。

        需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数来自动完成操作。

 📂 使用

#include <iostream>
#include <queue>

using namespace std;

int main()
{
    //默认建大堆
    //等价于 priority_queue<int,vector<int>,less<int>>
    priority_queue<int> p1;    

    //传递仿函数 , 建小堆
    priority_queue<int,vector<int>,greater<int>> p2;

    p1.push(1);
    p1.push(2);
    p1.push(3);

    p2.push(3);
    p2.push(2);
    p2.push(1);

    //p1 : 3,2,1
    //p2 : 1,2,3
}

 📂 仿函数

        仿函数(Functor)是一种行为类似于函数的对象。在C++中,仿函数可以被当作函数使用,可以执行函数调用操作,并且可以具有自己的状态。

        通常情况下,仿函数是一个类,它重载了函数调用运算符operator()。通过重载该运算符,仿函数可以像函数一样被调用,接受参数并返回结果。重载了operator[]的类,就是仿函数。

        仿函数的对象可以像函数一样调用。

        仿函数可以控制比较逻辑,控制如何比较。

 📂 模拟实现

namespace exercise
{
	template <class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return  x > y;
		}
	};

	template<class T,class Container = vector<T>,class Compare = less<T>>
	class priority_queue
	{
	public:

		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]))
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& val)
		{
			_con.push_back(val);
			AdjustUp(_con.size() - 1);
		}

		void AdjustDown(int parent)
		{
			Compare com;

			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					child++;
				}

				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[child],_con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

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

		bool empty()
		{
			return _con.empty();
		}

		const T& top()
		{
			return _con[0];
		}

	private:
		Container _con;
	};

}

📁 容器适配器

 📂 概念

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

 📂 STL库中stack和queue的底层结构

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

 📂 deque介绍

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

        deque并不是真正连续的空间,而是由一端连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,底层结构如下:

        双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在deque的迭代器上,因此deque的迭代器的设计比较复杂。如图所示:

        deque的缺陷:

        和vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此效率比vector高。

        和list比较,其底层空间时连续的,空间利用率特别高,不需要存储额外字段。

        但是deque有一个致命缺陷,不适合遍历,因为在遍历时,deque的迭代器要频繁的区间所是否移动到某段小空间的边界,导致效率低下,在序列式场合中,肯呢个需要经常遍历,因此在实际中,需要线性结构时,大多数有限考虑vector和list,deque的应用不多,目前的一个应用就是.STL用其为stack和queue的底层容器类。

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

📁 总结

        以上,就是本期【C++杂货铺】stack和queue的主要内容了,包含了它stack,queue,priority_queue的介绍和使用方法,以及他们模拟实现他们的底层。

        此外,还介绍了仿函数是什么,就是一个冲在了operator()的类,使用它的对象就像使用函数一样。

        如果感觉本期内容对你有帮助,欢迎点赞,收藏,关注。Thanks♪(・ω・)ノ

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【迅为iMX6Q】开发板 Linux version 6.6.3 SD卡 启动

开发环境 win10 64位 VMware Workstation Pro 16 ubuntu 20.04 【迅为imx6q】开发板&#xff0c; 2G DDR RAM linux-imx 下载 使用 NXP 官方提供的 linux-imx&#xff0c;代码地址为&#xff1a; https://github.com/nxp-imx/linux-imx 使用 git 下载 linux-imx&#xff…

STM32学习和实践笔记(6):自己进行时钟配置的思路

在《STM32学习和实践笔记&#xff08;4&#xff09;: 分析和理解GPIO_InitTypeDef GPIO_InitStructure (d)-CSDN博客》 中&#xff0c;我了解到&#xff0c;在程序执行我们写的main函数之前&#xff0c;实际上先执行了一个汇编语言所写的启动文件&#xff0c;以完成相应的初始…

python爬虫-----爬虫解析—xpath(第十八天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Day:004(4) | Python爬虫:高效数据抓取的编程技术(数据解析)

XPath工具 浏览器-元素-CtrlF 浏览器-控制台- $x(表达式) Xpath helper (安装包需要科学上网) 问题 使用离线安装包 出现 程序包无效 解决方案 使用修改安装包的后缀名为 rar&#xff0c;解压文件到一个文件夹&#xff0c;再用 加载文件夹的方式安装即可 安装 python若使用…

功能测试_验证qq账号的合法性

案例&#xff1a;验证qq账号的合法性&#xff08;要求&#xff1a;6-10位的自然数&#xff09; 使用等价类设计用例案例&#xff1a; 步骤&#xff1a; 1:明确需求&#xff1a;qq账号的合法性 2:划分等价类&#xff1a;有效等价类、有效取值、无效等价类、无效取值 3&…

风电场智能化转型基于ARM工控机的HDMI数据实时监控显示

全球能源结构不断调整的大背景下&#xff0c;智能电网、太阳能发电、风能发电等清洁能源领域正经历着一场由技术创新引领的深刻变革。在这场变革中&#xff0c;ARM架构的工控机凭借其出色的性能、低功耗及高度可定制化的特点&#xff0c;正在成为能源管理系统的核心组件&#x…

ModStartCMS(支持Laravel 9)v8.3.0

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议&#xff0c;免费且不限制商业使用。 功能特性 丰富的模块市…

tailwindcss在manoca在线编辑智能感知

推荐一下monaco-tailwindcss库&#xff0c;它实现在monaco-editor网页在线编辑器中对tailwindcss的智能感知提示&#xff0c;在利用tailwindcss实现html效果布局。非常的方便。 生成CSS

python简单读取和索引.nc文件(气象小白入门版)

一、总代码 #数据下载&#xff0c;这里下载的是NCEP的气压数据&#xff0c;在命令行运行代码即可 #wget -P /mnt/g/st_touchfish_py/data ftp://ftp.cdc.noaa.gov/Datasets/ncep.reanalysis.derived/pressure/air.mon.mean.ncimport xarray as xr import pandas as pd import …

51单片机ESP8266WiFi模块简介

乐鑫与安信可关系 乐鑫是生产esp8266芯片的厂家&#xff0c;安信可是基于esp8266芯片生产模组的厂家&#xff0c;所谓模组是基于芯片制作的套件。 波特率 ESP8266系列模组出厂使用的是AT固件&#xff0c;默认波特率是115200。实际上&#xff0c;模组在上电过程中首先是在748…

43.基于SpringBoot + Vue实现的前后端分离-疫苗发布和接种预约系统(项目 + 论文)

项目介绍 本次使用Java技术开发的疫苗发布和接种预约系统&#xff0c;就是运用计算机来管理疫苗接种预约信息&#xff0c;该系统是可以实现论坛管理&#xff0c;公告信息管理&#xff0c;疫苗信息管理&#xff0c;医生管理&#xff0c;医院信息管理&#xff0c;用户管理&#x…

【算法深度探索】动态规划之旅(1):挑战OJ题海,解锁15道经典难题,让你成为DP大师!

&#x1f4c3;博客主页&#xff1a; 小镇敲码人 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f30f; 任尔江湖满血骨&#xff0c;我自踏雪寻梅香。 万千浮云遮碧月&#xff0c;独傲天下百坚强。 男儿应有龙…

uniapp小程序下载并导出excel

<button click"confirmExport">导出excel</button>confirmExport() {let header {"X-Access-Token": uni.getStorageSync(ACCESS_TOKEN), //自定义请求头信息} let url "http"/......"; // 后端API地址uni.request({url: ur…

Java(多线程)

一、基本概念 进程&#xff1a;一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元&#xff0c;在传统的操作系统中&#xff0c;进程既是基本的分配单元&#xff0c;也是基本的执行单元。线程&#xff1a;操作系统中能够进行运算的最…

比较好玩的车子 高尔夫6

https://www.sohu.com/a/484063087_221273 四万多如愿收获手动挡高尔夫6&#xff0c;可靠性、经济性、操控性兼顾_搜狐汽车_搜狐网 2.基本上其他人也不知道到底是什么相关的车子信息

【算法刷题】八大排序算法总结(冒泡、选择、插入、二分插入、归并、快速、希尔、堆排序)

文章目录 八大排序算法总结1.冒泡排序2.选择排序3.插入排序4.二分插入排序5.归并排序6.快速排序7.希尔排序8.堆排序 八大排序算法总结 排序排序方法平均情况最好情况最坏情况空间稳定性1冒泡排序O(n2)O(n)O(n2)O(1)稳定2选择排序O(n2)O(n2)O(n2)O(1)不稳定3插入排序O(n2)O(n)O…

java io模型

一、五种IO模型 在《Unix网络编程》一书中提到了五种IO模型&#xff0c;分别是&#xff1a;阻塞IO、非阻塞IO、多路复用IO、信号驱动IO以及异步IO。 而Reactor模式实现了同步非阻塞模型&#xff0c;而Proactor模式实现了异步非阻塞模型 具体方面请参考我的另一篇博客 网络io…

Spring Validation解决后端表单校验

NotNull&#xff1a;从前台传递过来的参数不能为null,如果为空&#xff0c;会在控制台日志中把message打印出来 Range&#xff1a;范围&#xff0c;最大多少&#xff0c;最小多少 Patten&#xff0c;标注的字段值必须符合定义的正则表达式&#xff08;按照业务规则&#xff0…

车队试验的远程实时显示方案

风丘科技推出的数据远程实时显示方案更好地满足了客户对于试验车队远程实时监控的需求&#xff0c;并真正实现了试验车队的远程管理。随着新的数据记录仪软件IPEmotion RT和相应的跨平台显示解决方案的引入&#xff0c;让我们的客户端不仅可在线访问记录器系统状态&#xff0c;…

Go语言中的互斥锁(Mutex)和读写锁(RWMutex)

Mutex Mutex结构体 type Mutex struct {state int32 //表示互斥锁的状态,比如是否被锁定等sema uint32 //表示信号里,协程阻塞等待的信号量,解锁的协程释放信号量从而唤醒等待信号量的协程 } Locked: 表示Mutex是否已被锁定(1表示已经被锁定)Woken: 表示是否有协程被唤醒(1已有…