stack、queue、priority_queue

news2025/2/23 4:37:02

容器适配器

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

其中stack和queue都是容器适配器,其中stack可以封装vector、list以及我们后面要提到的deque,而由于queue是先进先出,所以实现的头删,因此封装的只有list和deque。

具体是怎么实现的我们在模拟实现的时候提一下


stack

template<class T>
class stack
{
public:
private:
	vector<int> st;
};

想要实现封装,我们可以采用上面的方式,但我们在上面也提到了,stack可以封装的容器不止一种,因此,我们就可以把容器也作为一个模板参数

template<class T,class Container>
class stack
{
public:
private:
	Container _con;
};

而在源码中,为模板参数Container提供了一个缺省值为deque<T>

template<class T,class Container = deque<T>>
class stack
{
public:
private:
	Container _con;
};

 之后就只剩下类成员函数的实现了,stack常用的就那么几个empty、size、top、pop、push,前两个都是容器中现有的函数,而top、pop、push分别对应着back、pop_back以及push_back,而所封装的容器必须要有上面这些函数,这也就是为什么会选择vector、list和后面的deque

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

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

		void pop()
		{
			_con.pop_back();
		}
	private:
		Container _con;
	};

queue

与stack类似,只是top变为了front和back,而push、pop对应push_back、pop_front

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

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

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

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

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

	void pop()
	{
		_con.pop_front();
	}
private:
	Container _con;

deque

deque,其实就是一个vector与list的结合,可以实现头删、头插、尾删、尾插。但说是结合,其实使用场景非常有限,所以我们就简单讲讲原理是什么样的

首先呢,deque内部有一个中控器,存放的是众多数组的首元素地址

而这些数组就是用来存放数据的,形式上有点类似于我们动态模拟的二维数组

这些数组的容量大小都是固定的,在一个数组没存满之前尾插依次在后面存放

而在存满后,再进行尾插会开辟一个新的数组,地址存放在中控器的尾端的下面

 而若是进行头插,若是头部的数组满了,则开辟一个新的数组,地址存放在头部的上面

而无论满还是没满,都需要从后向前存放

这样,便可以实现头插、头删、尾插、尾删

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

与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

因此,deque才作为默认类去进行stack和queue的封装

同样,我们上面说了,deque具有很大的局限性:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,因此,deque才只适合类似于stack和queue这样的适配器。


priority_queue

它也是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。说人话就是一个大堆,而其实,它本质是一个堆,只是在模板参数中有一个决定大小比较的仿函数,而它的缺省值(less)决定了它是一个大堆,当然我们也以传入库中的另一个(greater)来使他称为小堆。

首先我们先来简单的使用一下

void test1()
{
	priority_queue<int> heap1;
	heap1.push(1);
	heap1.push(3);
	heap1.push(4);
	heap1.push(2);
	while (heap1.size())
	{
		cout << heap1.top() << ' ';
		heap1.pop();
	}
	cout << endl;
	priority_queue<int,vector<int>,greater<int>> heap2;
	heap2.push(1);
	heap2.push(3);
	heap2.push(4);
	heap2.push(2);
	while (heap2.size())
	{
		cout << heap2.top() << ' ';
		heap2.pop();
	}
}

其实,接口还是那么几个,size、empty、top、push、pop

而有一点需要注意,当存放自定义类型的数据的时候,由于greater、less内部需要进行大小比较,因此我们需要在自定义类型内部重载一下>和<

模拟实现

在二叉树中,我们已经对堆进行了讲解,所以关于内部接口的实现就稍微一提,我们需要注意的就是仿函数这一概念

而仿函数本质上是一个类,拿less来说,通过传入的两个数,直接在构造函数中对这两个数进行比较,并返回其结果,

template<class T>
struct less
{
	bool operator()(const T& left, const T& right)
	{
		return left < right;
	}
};
template<class T>
struct greater
{
	bool operator()(const T& left, const T& right)
	{
		return left > right;
	}
};

由于这个类只需要在比较的这一行代码中起作用,因此我们在实例化时可以使用匿名对象

例如在比较父节点和子节点时

Compare()(c[parent], c[child])

之后,我们便只需要将之前堆学过的那些东西封装成接口,并将比较改用仿函数就可以了

namespace szt
{
	template<class T>
	struct less
	{
		bool operator()(const T& left, const T& right)
		{
			return left < right;
		}
	};

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

	template<class T, class Container = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		priority_queue() : c() {}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: c(first, last)
		{
			int count = c.size();
			int root = ((count - 2) >> 1);
			for (; root >= 0; root--)
				AdjustDown(root);
		}

		void push(const T& data)
		{
			c.push_back(data);
			AdjustUP(c.size() - 1);
		}

		void pop()
		{
			if (empty())
				return;

			swap(c.front(), c.back());
			c.pop_back();
			AdjustDown(0);
		}

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

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

		const T& top()const
		{
			return c.front();
		}
	private:
		void AdjustUP(int child)
		{
			int parent = ((child - 1) >> 1);
			while (child)
			{
				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					child = parent;
					parent = ((child - 1) >> 1);
				}
				else
				{
					return;
				}
			}
		}

		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < c.size())
			{
				if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))
					child += 1;

				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}
	private:
		Container c;
	};
}

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

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

相关文章

ffmpeg无损裁剪、合并视频

我用的版本是 ffmpeg version git-2020-06-23-ce297b4 官方文档 https://ffmpeg.org/ffmpeg-utils.html#time-duration-syntax 时间格式 [-][HH:]MM:SS[.m...] 或 [-]S[.m...][s|ms|us]裁剪视频 假设需要裁剪视频aaa.mp4&#xff0c;第5秒到第15秒 ffmpeg -ss 5 -to 15 -i…

使用gazebo对scara机械臂进行仿真

本文主要介绍如何仿真一个scara机械臂&#xff0c;以及在网上看了一些项目以后&#xff0c;有了一些感想&#xff0c;不想看的可以直接跳到机械臂部分。 目录感想(自己的理解&#xff0c;不一定对。)Scara机械臂的开发运动学计算如何使用机械臂工作图一个例子: 在start_pose抓起…

【Hadoop】MapReduce分布式计算实践(统计文本单词数量)

文章目录1. 前言2. Mapper代码3. Reducer代码4. Main代码5. 项目打包6. Hadoop运行7. 运行结果查看7.1 输出文件查看7.2 日志查看1. 前言 在博客【Hadoop】MapReduce原理剖析&#xff08;Map&#xff0c;Shuffle&#xff0c;Reduce三阶段&#xff09;中已经分析了MapReduce的运…

ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)

随着技术的进步&#xff0c;跨平台开发已经成为了标配&#xff0c;在此大背景下&#xff0c;ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例&#xff0c;简述基于MVC三层架构开发的常见知识点&#xff0c;前一篇文章&#xf…

Linux C编程一站式学习笔记6

Linux C编程一站式学习笔记 chap6 循环结构 文章目录Linux C编程一站式学习笔记 chap6 循环结构一.while语句递归 VS 循环函数式编程&#xff08;Functional Programming&#xff09; & 命令式编程&#xff08;Imperative Programming&#xff09;无限递归 & 无限循环习…

光流估计(二) FlowNet 系列文章解读

在上篇文章中&#xff0c;我们学习并解了光流&#xff08;Optical Flow&#xff09;的一些基本概念和基本操作&#xff0c;但是传统的光流估计方法计算比较复杂、成本较高。近些年来随着CNN卷积神经网络的不断发展和成熟&#xff0c;其在各种计算机视觉任务中取得了巨大成功&am…

docker-基础实战第六课镜像挂载

镜像挂载: docker run --namemynginx -d --restartalways -p 8088:80 -v /usr/local/docker/data/html:/usr/share/nginx/html:ro nginx访问403 原因: /usr/local/docker/data/html 没有创建index.html 需要创建目录并且创建index.html docker命令补充&#xff1a; 如果有一…

向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第1种方法)

1.前言 工作中经常会遇到这样的需求&#xff1a;向QAbstractItemView子类如QTreeView、QTableView单元格插入窗体小部件&#xff0c;如&#xff1a;进度条、按钮、单行编辑框等。下面链接的系列博文就是讲解如何实现该功能的。《向QAbstractItemView子类如:QTreeView、QTableVi…

Android音频播放有杂音?原来是这个JAVA API接口惹的祸

最近在调试一个基于十年前Android版本的多媒体应用软件时&#xff0c;遇到了音频播放的问题&#xff0c;这里记录问题的发现、分析和处理过程。 有人可能会好奇&#xff0c;十年前的Android版本是什么版本&#xff1f;大家可以去Google网站上查查&#xff0c;就是目前Android网…

Android深入系统完全讲解(40)

调试 C 代码 15.1 改成 C 写法 这个没啥必要&#xff0c;但是对 C 比 C 情谊深的我&#xff0c;把它修改了。下面是修改的一部分代码&#xff0c; 把 C 的写法&#xff0c;改成 C 的&#xff0c;同时修改引入头文件。 jstring Java_hellojni_codegg_com_hellojni_MainActivity_…

Java基础41 面向对象(高级)

面向对象&#xff08;高级&#xff09;一、类变量和类方法1.1、static &#xff08;类变量&#xff09;1.1.1 关于static的存放位置1.1.2 类变量使用细节及注意事项1.2、类方法1.2.1、类方法使用细节及注意事项二、main方法2.1、深入理解main方法三、代码块3.1、代码块的基本介…

19.6、Javaweb_案例旅游路线收藏功能

旅游线路收藏功能 分析 判断当前登录用户是否收藏过该线路 当页面加载完成后&#xff0c;发送ajax请求&#xff0c;获取用户是否收藏的标记 根据标记&#xff0c;展示不同的按钮样式 编写代码 后台代码 RouteServlet&#xff1a; package cn.itcast.travel.web.servlet;…

【Typescript学习】使用 React 和 TypeScript 构建web应用(四)useReducer、扑街了的分区功能【完结了】

教程来自freecodeCamp&#xff1a;【英字】使用 React 和 TypeScript 构建应用程序 跟做&#xff0c;仅记录用 其他资料&#xff1a;https://www.freecodecamp.org/chinese/news/learn-typescript-beginners-guide/ 作者提供的源码https://github.com/piyush-eon/react-typescr…

机器学习【西瓜书/南瓜书】--- 第四章决策树

一、决策树理论分析 1.1 通俗理解 决策树是一种非常经典的机器学习算法&#xff0c;通俗理解的话我们可以举一个例子&#xff0c;比如现在别人要找你借钱&#xff0c;那么按照首先是不是要判断你和他的关系如何?如果关系不好&#xff0c;我就直接拒绝他。如果关系很好&#…

Python机器学习:一元回归

→\rightarrow→回归效果评价 &#x1f315; 一元回归 一元回归主要研究一个自变量和一个因变量之间的关系&#xff0c;而这个自变量和因变量之间的关系又可分为线性回归和非线性回归。 ⭐️ 一元线性回归分析两个变量之间的线性关系&#xff0c;如ykxbykxbykxb中xxx和yyy就是…

深度学习笔记:神经网络的学习(1)

机器学习的核心在于从数据中提取规律和特征&#xff0c;并用于分类或预测。对于识别手写数字&#xff0c;如果人工设计一个识别算法逻辑是十分困难的。一种方法是任务在数据中提取更重要的特征量&#xff0c;然后利用机器学习算法如SVM或KNN。而神经网络的方法则是完全由机器自…

ISIS的3级别(level-1、level-2、level-1-2)4大类(IIH、LSP、CSNP、PSNP)9小类与邻接关系建立LSP交互过程介绍

2.2.0 ISIS 4种报文类型IIH、LSP、CSNP、PSNP、邻居建立过程、交互LSP过程 ISIS的3级别4大类9小类 ISIS拥有3种级别的路由器&#xff0c;分别是level-1、level-2、level-1-2。 不同级别之间进行交互的报文也是有所区别的&#xff0c;常规的ISIS报文分有4大类&#xff1a;IIH、…

cubeIDE开发, stm32人工智能开发应用实践(Cube.AI).篇一

一、cube.AI简介及cubeIDE集成 1.1 cube.AI介绍 cube.AI准确来说是STM32Cube.AI&#xff0c;它是ST公司的打造的STM32Cube生态体系的扩展包X-CUBE-AI&#xff0c;专用于帮助开发者实现人工智能开发。确切地说&#xff0c;是将基于各种人工智能开发框架训练出来的算法模型&#…

Vue3商店后台管理系统设计文稿篇(六)

记录使用vscode构建Vue3商店后台管理系统&#xff0c;这是第六篇&#xff0c;从这一篇章开始&#xff0c;所有的预备工作结束&#xff0c;正式进入商店后台管理系统的开发 文章目录一、创建后台管理系统的标题栏二、安装Icon 图标三、创建Menu菜单正文内容&#xff1a; 一、创…

PowerShell 学习笔记:操作JSON文件

JSON文件&#xff08;字符串&#xff09;是有一定格式要求的文本文件。百度百科JSON&#xff08;JavaScriptObject Notation, JS对象简谱&#xff09;是一种轻量级的数据交换格式。它基于 ECMAScript&#xff08;European Computer Manufacturers Association, 欧洲计算机协会制…