【C++】学习STL中的stack和queue

news2024/11/29 12:37:41

❤️前言

        今天这篇博客的内容主要关于STL中的stack、queue和priority_queue三种容器。

正文

        stack和queue的使用方式非常简单,我们只要根据之前学习数据结构的经验和文档介绍就可以轻松上手。于是我们直接开始对它们的模拟实现。

stack和queue的模拟实现

        stack和queue我们在数据结构阶段就曾经学习过,它们的底层结构都可以基于其他的基本数据结构进行实现。这时候我们就可以用到上篇文章中提到过的适配器模式来实现这两个模板。

        实现方式只要遵从栈和队列的规则即可,代码如下:

template<typename T, typename Container = deque<T>>
class stack
{
public:
	bool empty() const
	{
		return _con.size() == 0;
	}

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

	T& top()
	{
		return *(--_con.end());
	}

	const T& top() const
	{
		return *(--_con.end());
	}

	void push(const T& x)
	{
		_con.insert(_con.end(), x);
	}

	void pop()
	{
		_con.erase(--_con.end());
	}

private:
	Container _con;
};


template<typename T, typename Container = deque<T>>
class queue
{
public:
	void push(const T& x)
	{
		_con.insert(_con.end(), x);
	}

	void pop()
	{
		_con.erase(_con.begin());
	}

	T& back()
	{
		return *(--_con.end());
	}

	const T& back() const
	{
		return *(--_con.end());
	}

	T& front()
	{
		return *(_con.begin());
	}

	const T& front() const
	{
		return *(_con.begin());
	}

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

	bool empty() const
	{
		return _con.size() == 0;
	}
private:
	Container _con;
};

        这里我们在使用这两个模板的时候可以传入两个模板参数,分别为数据类型和空间适配器类型,对于stack这样的容器,我们可以传入vector作为空间适配器,因为它的规则是后进先出,我们只需要关注尾插尾删即可,这样使用vector的效率是很高的。同理,我们在使用queue时可以传入list作为空间适配器。使用了适配器模式,我们的代码更加的简洁高效。

        除此之外,这里我们需要简单了解一下双端队列(deque),也就是上面给出的默认空间适配器。deque结合了数组和链表的特点,本来是设计出来准备替代它们的产物,但是显而易见,它失败了(不然现在我们就不会学数组和链表了)。作为结合数组和链表的产物,它的随机访问效率低于vector,中间插入删除效率也很低,虽然它缓解了一些vector和list本身的问题,但是它总归替代不了vector和list。可以说,deque的优势就是头插头删、尾插尾删效率很高,这非常适合用来适配stack和queue

优先级队列priority_queue

        优先级队列(priority_queue)在数据结构中对应我们之前学的数据结构中的堆,堆的使用也非常简单,我们只要大概看看文档即可。除此之外堆根据堆内元素之间的关系被分为大根堆和小根堆,堆的堆顶元素是整个堆中的最值,这可以帮我们解决经典的Top-k问题。

优先级队列的模拟实现

        在数据结构二叉树的学习阶段我们已经实现过堆的各种接口,只要稍加改动设计就成了一个优先级队列的模板,代码实现如下:

template<typename T, typename Container = std::vector<T>, typename Compare = std::less<T>>
class priority_queue
{
private:
	void AdjustDown(int parent)
	{
		int child = 2 * parent + 1;
		while (child < _con.size())
		{
			if (child + 1 < _con.size() && _cmp(_con[child], _con[child+1])) child++;
			if (_cmp(_con[parent], _con[child]))
			{
				std::swap(_con[parent], _con[child]);
				parent = child;
				child = 2 * parent + 1;
			}
			else
			{
				break;
			}
		}   
	}

	void AdjustUp(int child)
	{
		int parent = (child - 1) / 2;
		while (parent >= 0)
		{
			if (_cmp(_con[parent], _con[child]))
			{
				std::swap(_con[parent], _con[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
public:
	priority_queue() {}

	template <typename InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			_con.insert(_con.end(), *first);
			first++;
		}
	}

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

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

	const T& top() const
	{
		return *(_con.begin());
	}

	void push(const T& x)
	{
		_con.insert(_con.end(), x);
		AdjustUp(_con.size() - 1);
	}

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

private:
	Container _con;
	Compare _cmp;
};

        首先我们看到优先级队列有三个模板参数,除了存储数据类型以外,还有空间适配器和仿函数。空间适配器想必大家比较熟悉了,对于堆来说,比较适合的类型就是数组vector。仿函数之前大家没有遇到过,这里为大家附上一个博客链接,大家可以看看:

C++ 仿函数_仿函数 c++_恋喵大鲤鱼的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/K346K346/article/details/82818801        简单来说,仿函数就是一类可以当作函数使用的类,它具有和函数指针类似的作用,让我们可以轻松地控制生成许多效果不同的类,减少了代码冗余。

        而在优先级队列中,这个仿函数的作用是比较堆节点的大小关系,于是通过改变仿函数的种类,我们能够控制大小堆以及元素间比较的方式,优先级队列的默认仿函数为less,也就是默认的大根堆,这点需要注意。

        当然,在实现优先级队列的过程中,调整位置的算法是比较难的点,也希望大家能够多加练习巩固。

🍀结语

        以上就是今天博客的所有内容啦,希望能够帮助到大家。

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

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

相关文章

redis实战-实现优惠券秒杀解决超卖问题

全局唯一ID 唯一ID的必要性 每个店铺都可以发布优惠券&#xff1a; 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题&#xff1a; id的规律性太明显&#xff0c;容易被用户根据id的间隔来猜测…

不同路径【动态规划】

不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f;…

python 美国总统身高统计与分析

美国总统身高统计与分析 1.安装依赖2.下载数据集3.数据处理4.结果展示 1.安装依赖 pip install pandas pip install numpy pip install matplotlib2.下载数据集 链接&#xff1a;https://pan.baidu.com/s/1aZLtkLyvQvRLb9tJ-B1krA 提取码&#xff1a;thms –来自百度网盘超级…

Spring Cloud 系列之OpenFeign:(8)链路追踪续

传送门 Spring Cloud Alibaba系列之nacos&#xff1a;(1)安装 Spring Cloud Alibaba系列之nacos&#xff1a;(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos&#xff1a;(3)服务注册发现 Spring Cloud 系列之OpenFeign&#xff1a;(4)集成OpenFeign Spring Cloud …

无涯教程-JavaScript - CUBEMEMBERPROPERTY函数

描述 CUBEMEMBERPROPERTY函数从多维数据集返回成员属性的值。使用此函数可以验证多维数据集中是否存在成员名称,并返回该成员的指定属性。 语法 CUBEMEMBERPROPERTY (connection, member_expression, property)争论 Argument描述Required/OptionalconnectionName of the co…

Glide的使用及源码分析

前言 依赖 implementation com.github.bumptech.glide:glide:4.16.0 github: GitHub - bumptech/glide: An image loading and caching library for Android focused on smooth scrolling 基本使用 //加载url Glide.with(this) .load(url) .placeholder(R.drawable.placehol…

Python 没有 pip 包问题解决

最近需要搞一个干净的Python,从官网上直接下载解压可用的绿色版&#xff0c;发现无法正常使用PiP 一 官网下载Python https://www.python.org/downloads/ 选择 embeddable package,这种是免安装的包&#xff0c;解压后可以直接使用。 二 配置环境变量 添加环境变量&#xff1a…

Cortex-A7 架构

参考《 Cortex-A7 Technical ReferenceManua.pdf 》和《 ARM Cortex-A(armV7) 编程手 册 V4.0.pdf 》 【 正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6学习 1.Cortex-A7 MPCore 简介 I.MX6UL 使用的是 Cortex-A7 架构&#xff0c;Cortex-A7 MPcore 处理器支持 1~4 核&#…

【云原生进阶之PaaS中间件】第一章Redis-1.3Redis配置

1 Redis配置概述 Redis支持采用其内置默认配置的方式来进行启动&#xff0c;而不需要提前配置任何文件&#xff0c;但是这种启动方式只推荐在测试和开发环境中使用&#xff0c;但更好的方式是通过提供一个Redis的配置文件来对Redis进行配置&#xff0c; 这个配置文件一般命名为…

常用的msvcp140.dll丢失的解决方法,msvcp140.dll丢失的原因

自从电脑出现故障&#xff0c;我的生活变得一团糟。他每天都需要使用电脑处理工作&#xff0c;可是突然有一天&#xff0c;他发现许多软件和游戏都无法正常运行。错误提示显示“找不到msvcp140.dll”&#xff0c;这让他感到非常困扰。今天想和大家分享一个在计算机使用过程中经…

Docker进阶:mysql 主从复制、redis集群3主3从【扩缩容案例】

Docker进阶&#xff1a;mysql 主从复制、redis集群3主3从【扩缩容案例】 一、Docker常规软件安装1.1 docker 安装 tomcat&#xff08;默认最新版&#xff09;1.2 docker 指定安装 tomcat8.01.3 docker 安装 mysql 5.7&#xff08;数据卷配置&#xff09;1.4 演示--删除mysql容器…

【计算机组成 课程笔记】4.2 除法器的硬件实现

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 4 - 5 - 405-除法的运算过程&#xff08;09-43--&#xff09;_哔哩哔哩_bilibili 在加减乘除这样的基本算数运算中&#xff0c;除法是最为复杂的&#xff0c;因此我们想要实现硬件的除法器&#xff0c;还是从最简…

yolov2相较于yolov1的改进

目录 前言 BN层取代了Dropout 使用了高分辨率分类器 K-means选定先验框的尺寸 网络结构—darknet19 细粒度的特征 前言 yolov2是在yolov1的基础上进行改进的&#xff0c;主要解决了yolov1定位不准确以及检测重叠的物体极差的情况&#xff0c;总的来说&#xff0c;它有以下…

使用pip命令安装python第三方库有效方法合集

本文摘要&#xff1a;本文提出了4种实用的pip命令安装python第三方库有效方法合集 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智…

【代码技巧】深度学习参数管理方案(1)

方法概述 利用argparse工具包进行参数管理 创建BaseOptions类进行基础参数的管理&#xff0c;在建立TrainOptions和TestOpetions继承BaseOptions的基础参数&#xff0c;然后可以再添train或者test阶段的新的参数。 文件结构 创建三个文件如图&#xff0c;分别管理BaseOption…

机器学习之 Jupyter Notebook 使用

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

msvcr120.dll文件丢失的解决方法,四种快速解决发方法分享

你是否曾经在使用电脑时遭遇过 msvcr120.dll 文件丢失的困扰&#xff1f;如果你对此感到茫然无措&#xff0c;那么请跟随我的脚步&#xff0c;让我们一起探索这个问题的根源。当我一如既往地打开电脑&#xff0c;准备开始一天的工作时&#xff0c;突然发现许多应用程序无法正常…

数学建模:回归分析

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 数学建模&#xff1a;回归分析 文章目录 数学建模&#xff1a;回归分析回归分析多元线性回归案例 多项式回归一元多项式回归多元二项式回归 非线性回归逐步回归 回归分析 多元线性回归 案例 首先进行回归分…

用C语言,编写一个这样的程序,满足五日均线,十日均线,二十日均线,六十天六日均线调头向上的选股代码

用C语言&#xff0c;编写一个这样的程序&#xff0c;满足五日均线&#xff0c;十日均线&#xff0c;二十日均线&#xff0c;六十天六日均线调头向上的选股代码&#xff0c;我来做个案例。 #include <stdio.h> #include <stdlib.h> #define MAX_ROWS 1000 // 假设数…

【小吉送书—第一期】Kali Linux高级渗透测试

文章目录 &#x1f354;前言&#x1f6f8;读者对象&#x1f388;本书资源&#x1f384;彩蛋 &#x1f354;前言 对于企业网络安全建设工作的质量保障&#xff0c;业界普遍遵循PDCA&#xff08;计划&#xff08;Plan&#xff09;、实施&#xff08;Do&#xff09;、检查&#x…