当前位置: 首页 > article >正文

STL中queue、stack的实现与容器适配器的讲解

目录

简介

栈(Stack)

队列(Queue)

实现

栈的实现

队列的实现

deque的讲解

deque的结构示意图


简介

栈(Stack)和队列(Queue)是两种基本的数据结构,在STL(Standard Template Library,标准模板库)中,它们被封装为容器适配器,用于管理元素的插入和删除操作。

栈(Stack)

栈是一种后进先出(Last In First Out, LIFO)的数据结构。在STL中,栈的接口定义如下:

  • push():在栈顶插入一个元素。
  • pop():删除栈顶元素。
  • top():返回栈顶元素的引用。
  • empty():检查栈是否为空。
  • size():返回栈中元素的数量。

栈通常用于以下场景:

  • 递归算法的实现。
  • 实现后退功能,如浏览器的后退按钮。
  • 解决问题时的临时存储,如深度优先搜索(DFS)。

队列(Queue)

队列是一种先进先出(First In First Out, FIFO)的数据结构。在STL中,队列的接口定义如下:

  • push():在队列末尾插入一个元素。
  • pop():删除队列首部的元素。
  • front():返回队列首部元素的引用。
  • back():返回队列末尾元素的引用。
  • empty():检查队列是否为空。
  • size():返回队列中元素的数量。

队列通常用于以下场景:

  • 在多任务处理中管理任务,如线程池。
  • 实现广度优先搜索(BFS)。
  • 缓存实现,如最近最少使用(LRU)缓存。

在STL中,栈和队列通常是基于deque(双端队列)或list(链表)来实现的,但用户不需要关心底层实现细节,可以直接使用它们提供的接口来进行操作。这两种数据结构都是模板类,可以存储任何类型的元素。

由于我们需要深度学习这两种数据结构,因此本文将实现stack与queue

实现

栈的实现

栈可分数组站、链表栈,都可以实现后进先出的功能。我们可以采用C语言中借助一个动态指针等方式实现。但是在C++中,可以借助其他容器实现。

对于stack而言,既可以使用list,也可以使用vector、、、

template<class T, class Container = std::deque<T>>
class stack
{

官网中stack的实现借助的是模板

因此我们也借助模板实现。

模板参数由数据类型T和容器类型Container构成。

栈的功能函数

栈主要是top        pop        push这三个核心函数构成。


namespace My_Stack
{
	template<class T, class Container = std::deque<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

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

		const T& top() const
		{
			return _con.back();		//back不是front
		}

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

		size_t size() const
		{
			return _con.size();
		}
	private:
		Container _con;		//默认生成的构造函数,会调用_con的构造
	};

}

需要注意的是:

对于构造函数、析构函数等内置函数,我们并没有显式实现。系统默认生成的构造函数会自动调用_con该容器的构造,析构函数也会调用该容器的析构完成资源的清理。

top是栈顶元素,也就是容器的最后一个元素。

队列的实现

队列也是一个模板类,但是队列的容器不能是vector,原因是vector没有pop_front()函数,而队列需要大量的先进先出。

#include <deque>

namespace My_Queue
{
	template<class T, class Container = std::deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

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

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

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

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

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

	private:
		Container _con;
	};


}

deque的讲解

可以看到,我们在实现队列和栈的时候,都利用了deque,这是什么呢?

Deque(双端队列)是一种数据结构,它允许在队列的两端进行插入和删除操作。它是“double-ended queue”的缩写,有时也被称为双端队列容器

在 C++ 的 STL(标准模板库)中,deque 与 vector 容器有很多相似之处,但它们之间也存在一些关键的区别。与 vector 不同的是,deque 在队列的两端(头部和尾部)添加或删除元素的效率都非常高,时间复杂度为 O(1)。这意味着 deque 在频繁进行头部或尾部操作时,比 vector 更高效

其实deque同样可以成为完成栈和队列的容器。

以下是 deque 的一些特点:

  1. 双向开口:deque 是一种双向开口的连续线性空间,允许在头尾两端分别进行元素的插入和删除操作。

  2. 动态空间管理:deque 没有固定的容量概念,它是动态地以分段连续空间组合而成,可以根据需要随时增加新的空间。

  3. 高效的头尾操作:与 vector 相比,deque 在头部进行插入和删除操作时效率更高,因为不需要移动所有元素。

  4. 迭代器:deque 的迭代器需要能够指出分段连续空间的位置,并且能够判断是否处于当前缓冲区的边缘。如果是,则在进行前进或后退操作时,需要跳跃到下一个或上一个缓冲区。

如下是deque的函数

看函数,像是list与vector的结合体。它既能实现list的功能,也能实现vector的功能。那为什么不能deque呢?主要还是,他什么都会,但是什么都不精通

因此,根据需求,我们还是主要使用list和vector。但是,当需要在序列的两端频繁进行添加或删除操作时,deque 容器是一个很好的选择。

deque的结构示意图

deque其实是一个中控数组实现,数组中存放着一个个的指针,指向了其他容器(一般被乘坐buffer)。

其实,本质是个指针数组!

头插与尾插示意图

头插:在10之前

中控满了,可以去扩容,但是代价低,因为这只是一个指针数组,只需要拷贝指针。

但是在内部插入删除元素,就显得效率极其低下!因为要么得整体挪动数据,以保证buffer的大小一致,方便[]访问;要么得对单个的buffer扩容,或者减少数据。


http://www.kler.cn/a/282953.html

相关文章:

  • Shell 脚本中的大小写陷阱:为什么 ${PWD} 而不是 ${pwd}?
  • 动态规划问题-删除并获得点数(Java实现)
  • 第三十一天|贪心算法| 56. 合并区间,738.单调递增的数字 , 968.监控二叉树
  • 〔 MySQL 〕数据类型
  • 阅读2020-2023年《国外军用无人机装备技术发展综述》笔记_技术趋势
  • 大厂的 404 页面都长啥样?看看你都见过吗~~~
  • C++入门篇1
  • 【前端面试】React深度学习(下)
  • 【软件测试】自动化测试如此盛行,手工测试该何去何从?
  • Shell脚本入门:多命令处理
  • wpf prism 《3》 弹窗 IOC
  • RabbitMQ练习(Publish/Subscribe)
  • GPT-SoVITS-WebUI 初体验
  • C++练习题:进阶算法——动态规划
  • 面试题集锦:数据库
  • 米壳AI:做塞尔维亚跨境电商,用这个工具翻译产品主图,语言不再是难题!
  • KEYSIGHT是德 Infiniium EXR系列 示波器
  • LavaDome:一款基于ShadowDOM的DOM树安全隔离与封装工具
  • 大语言模型中,role为user、assistant、system有什么区别
  • 我主编的电子技术实验手册(18)——认识电感
  • 【数学建模】国赛论文写作教学——问题重述与分析
  • HTML实现俄罗斯方块
  • Spire.PDF for .NET【文档操作】演示:创建标记的 PDF 文档
  • 3.服务注册_服务发现
  • 低代码技术:简化应用开发,推动数字化转型
  • 树莓派4B安装golang最新版(20210520)