【C++】拆分详解 - stack和queue

文章目录

  • 一、stack的介绍和使用
    • 1. 简介
    • 2. 使用
    • 3. 模拟实现
  • 二、queue的介绍和使用
    • 1. 简介
    • 2. 使用
    • 3. 模拟实现
  • 三、容器适配器
    • 1. 简介
    • 2. STL标准库中的使用
  • 四、deque(了解)
    • 1. 简介
    • 2. 底层原理
      • 2.1 底层空间
      • 2.2 模拟访问元素
      • 2.3 迭代器
      • 2.4 STL源码片段摘要
    • 3. 缺陷和使用场景
  • 五、priority_queue
    • 1. 简介
    • 2. 使用
    • 3. 模拟实现
      • 0. 仿函数
      • 1. 整体结构
      • 2. 构造
      • 3. 向上调整
      • 4. 向下调整
      • 5. 插入
      • 6. 删除
      • 7. top / size / empty
  • 总结

一、stack的介绍和使用

1. 简介

stack文档介绍

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。

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

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

    empty:判空操作

    back:获取尾部元素操作

    push_back:尾部插入元素操作

    pop_back:尾部删除元素操作

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 使用

接口名称功能说明
stack()无参构造空栈
empty()判断是否为空
size()获取有效元素个数
top()获取栈顶元素的引用
push()入栈
pop()出栈

3. 模拟实现

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

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

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

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

	private:
		Container _con;
	};
}

二、queue的介绍和使用

1. 简介

queue的文档介绍

  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。

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

  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

    empty:检测队列是否为空

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

    front:返回队头元素的引用

    back:返回队尾元素的引用

    push_back:在队列尾部入队列

    pop_front:在队列头部出队列

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

在这里插入图片描述

2. 使用

接口名称功能说明
queue()无参构造空队列
empty()判断是否为空
size()获取有效元素个数
front()获取队头元素的引用
back()获取队尾元素的引用
push()队尾入栈
pop()队头出栈

3. 模拟实现

template<class T, class Container = 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()
	{
		return _con.front();
	}

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

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

private:
	Container _con;
};

三、容器适配器

1. 简介

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设

计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

  • 迭代器也是一种设计模式

2. STL标准库中的使用

STL标准库中stack和queue的底层结构:

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

在这里插入图片描述

在这里插入图片描述

四、deque(了解)

1. 简介

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:

可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。(功能上为vector和list的结合体,就像骡子)

在这里插入图片描述

2. 底层原理

2.1 底层空间

(既不像vector那样使用一整块连续空间,也不像list那样全部使用节点,而是使用一小块一小块的连续空间 (buffer数组) 存储数组,然后使用一个指针数组存储这些小数组的指针)

  • 每个buffer数组长度相同,一个存满后就再开辟一个
  • 指针数组(中控数组)中存储buff数组首元素的地址(按顺序存储)

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

在这里插入图片描述
在这里插入图片描述

2.2 模拟访问元素

  1. 方法:

    设buffer数组长度为N,访问第x个元素:

    1. 从指针数组中找buffer:

      i = x / N ,找到该元素位于第i个buffer数组

    2. 从buffer中找元素:

      j = x % 10,找到该元素位于对应buffer数组的第j个位置

  2. 实例:

    在这里插入图片描述

  3. 思考:

    头插时,新创建的buff数组未满,该方法是否有问题?

在这里插入图片描述

2.3 迭代器

(整个deque的操作都是由迭代器来维护控制的) 双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


2.4 STL源码片段摘要

  • 迭代器相关定义

    在这里插入图片描述


    在这里插入图片描述

  • 模拟迭代器遍历调用过程

    在这里插入图片描述

  • 下标访问

    在这里插入图片描述

3. 缺陷和使用场景

  1. deque中间位置进行插入和删除也需要挪动元素,效率不高(等同于vector)
  2. 下标[]访问 在大量访问情景(如排序)下 效率远不及vector
  • 结论:

    给stack和queue作默认适配容器很合适:

    1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。

    2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

五、priority_queue

1. 简介

priority_queue(优先队列):

默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用

  • 默认情况下priority_queue是大堆。

  • 底层容器:默认为vector,需支持随机访问迭代器。

  • 堆维护:通过自动调用相关算法函数保持堆结构。

  • 使用场景:这些特性使得优先队列在需要频繁插入和检索最大元素的场景中非常高效。

2. 使用

接口名称功能说明
priority_queue()/priority_queue(first,last)空构造 / 迭代器区间构造
empty( )判断是否为空
top( )获取顶部元素
push(x)插入
pop( )删除顶部元素
void TestPriorityQueue()
{
	// 默认情况下,创建的是大堆,其底层按照小于号比较
	vector<int> v1 = { 3,2,7,6,0,4,1,9,8,5 };
	priority_queue<int> q1(v1.begin(), v1.end());

	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
	// 如果要创建小堆,将第三个模板参数换成greater比较方式(greater为一个仿函数,我们后面会进行讲解)
	priority_queue<int, vector<int>, greater<int>> q2(v1.begin(), v1.end());
	while (!q2.empty())
	{
		cout << q2.top() << " ";
		q2.pop();
	}
}

3. 模拟实现

0. 仿函数

  • 定义:就是一个重载了operator() 的类,使得该类的对象可以像函数一样使用(代替C语言的函数指针)

  • 简单示例:

    template<class T>
    class compare
    {
    public:
    	bool operator()(const T& x, const T& y)
    	{
    		return x == y;
    	}
    };
    
    
    int main()
    {
    	compare<int> f1;
    
    	//f1.operator()(10, 5); 一般类对象调用成员函数
    	f1(10, 5); //仿函数,像函数一样使用
    
    	return 0;
    }
    
  • 大于和小于比较

    template<class T>
    class myless
    {
    public:
    	bool operator()(const T& x, const T& y)
    	{
    		return x < y;
    	}
    };
    
    template<class T>
    class mygreater
    {
    public:
    	bool operator()(const T& x, const T& y)
    	{
    		return x > y;
    	}
    };
    

1. 整体结构

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

	//... 各类函数接口

private:
	Container _con;
}

2. 构造

//1. 强制生成默认构造(无参)
priority_queue() = default;

//2. 迭代器区间构造
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		_con.push_back(*first);
		++first;
	}

	for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
	{
		adjust_down(i);
	}
}

3. 向上调整

void adjust_up(int child)
{
	Compare comfunc; //定义仿函数对象
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//if(_con[parent] < _con[child])
		if(comfunc(_con[parent], _con[child]))
		//if (comfunc.operator()(_con[parent], _con[child]))
		{
			swap(_con[parent], _con[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

4. 向下调整

void adjust_down(int parent)
{
	Compare comfunc; // 同上

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

		//if (_con[parent] < _con[child])
		if (comfunc(_con[parent], _con[child]))
		{
			swap(_con[parent], _con[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

5. 插入

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

6. 删除

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

	adjust_down(0);
}

7. top / size / empty

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

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

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

总结

本文介绍了stack,list,deque,priority_queue,并对其中重点接口进行了模拟实现,以便读者了解其底层逻辑,有利于更好地使用。
尽管文章修正了多次,但由于水平有限,难免有不足甚至错误之处,敬请各位读者来评论区批评指正。

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

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

相关文章

高清无水印推文视频素材下载网站推荐

在制作抖音短视频时&#xff0c;选择合适的视频素材至关重要。想知道哪里可以下载热门的推文视频素材吗&#xff1f;别担心&#xff0c;我为你整理了六个高品质的视频素材网站&#xff0c;让我们一起来看看吧&#xff01; 蛙学网 首先介绍的是蛙学网&#xff0c;作为国内知名的…

期权懂|股票下跌时可以使用期权止损吗?

本期让我懂 你就懂的期权懂带大家来了解&#xff0c;股票下跌时可以使用期权止损吗&#xff1f;有兴趣的朋友可以看一下。期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 股票下跌时可以使用期权止损吗&#xff1f; 在股市中&am…

Oracle 使用位图索引 Cost降低200倍! 探讨位图索引的利与弊

一.简介 位图索引&#xff08;Bitmap Index&#xff09; 是 Oracle 数据库中一种特殊类型的索引&#xff0c;适用于低基数&#xff08;Low Cardinality&#xff09;列&#xff0c;即那些列中可选值相对较少的情况下使用。它与常规的 B-tree 索引不同&#xff0c;位图索引通过位…

MybatisPlus入门教程及实现基础的增删改查

此篇博客主要针对于有开发基础的朋友学习~ 首先提几个问题&#xff1a; 1、什么是Mybatis&#xff1f; 2、什么是MybatisPlus&#xff1f; 3、Mybatis和MybatisPlus又有什么区别呢&#xff1f; 问题1&#xff1a;Mybatis是一个持久层的框架&#xff0c;我们通过配置mapper.xm…

Linux 外设驱动 应用 2 KEY 按键实验

2 按键 2.1 按键介绍 按键是指轻触式按键开关&#xff0c;也称之为轻触开关。按键开关是一种电子开关&#xff0c;属于电子元器件类&#xff0c;最早出现在日本&#xff0c;称之为&#xff1a;敏感型开关&#xff0c;使用时以满足操作力的条件向开关操作方向施压开关功能闭合…

RabbitMQ系列学习笔记(三)--工作队列模式

文章目录 一、工作队列模式原理二、工作队列模式实战1、抽取工具类2、消费者代码3、生产者代码4、查看运行结果 本文参考 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、工作队列模式原理 与简单模式相…

MySQL中查询语句的执行流程

文章目录 前言流程图概述最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;今天我们一起探讨一下执行一条查询的SQL语句在MySQL内部都发生了什么&#xff0c;让你对MySQL内部的架构具备一个宏观上的了解 流程图 概述 对于查询语句的SQL的执行流程&#xff0c;主要可以分为…

架构师备考-背诵精华(系统架构评估)

系统架构评估是在对架构分析、评估的基础上&#xff0c;对架构策略的选取进行决策。它利用数学或逻辑分析技术&#xff0c;针对系统的一致性、正确性、质量属性、规划结果等不同方面&#xff0c;提供描述性、预测性和指令性的分析结果。 重要概念 敏感点&#xff1a;敏感点是…

信息学奥赛复赛复习18-CSP-J2022-01解密-二分答案、二分找边界、二分时间复杂度、二分求最小

PDF文档回复:20241017 1 P8814 [CSP-J 2022] 解密 [题目描述] 给定一个正整数 k&#xff0c;有 k 次询问&#xff0c;每次给定三个正整数 ni,ei,di&#xff0c;求两个正整数 pi,qi&#xff0c;使 nipiqi、eidi(pi−1)(qi−1)1 [输入格式] 第一行一个正整数 k&#xff0c;表…

单神经元建模:基于电导的模型[神经元结构、静息电位和等效电路]

文章目录 神经元结构、静息电位和等效电路神经元结构静息电位能斯特方程1. **描述浓度比的非线性关系**&#xff1a;2. **化学势与电势的关系**&#xff1a;3. **对称性**&#xff1a;4. **热力学与平衡**&#xff1a;总结&#xff1a; GHK方程Nernst方程和GHK方程的对比 等效电…

自动化检查网页的TDK,python+selenium自动化测试web的网页源代码中的title,Description,Keywords

首先&#xff0c;TDK是什么&#xff1f;对于新手小白来说&#xff0c;可能是懵逼的&#xff0c;所以这里给出一个官方的解说‌网页的TDK是指标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keywords&#xff09;的集合‌。这…

vue3播放m3u8格式hls监控流

1. 摄像头的hls监控流不同于普通m3u8的视频&#xff0c;video标签&#xff0c;iframe&#xff0c;videojs&#xff0c;vue-video-player无法解析 2. 解决办法 更换LivePlayer插件 官网https://www.liveqing.com/docs/manuals/LivePlayer.html#%E5%B1%9E%E6%80%A7-property 3…

Java项目-基于Springboot的招生管理系统项目(源码+说明).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Tkinter -- python GUI学习与使用

前言 python GUI 目前pythonGUI有很多&#xff0c;哪一个最好&#xff1f; 先说说我选择的思路&#xff0c;我的目的是开发一个易用的软件&#xff0c;最重要的是稳定&#xff0c;并且碰到问题能够解决&#xff0c;因此&#xff0c;我的目标很明确&#xff0c;有比较大的用户群…

cefsharp79.1.360(Chromium 79.0.3945.130)支持H264视频播放-PDF预览 老版本回顾系列体验

一、关于此版本 版本:Cef 79.1.36/CefSharp 79.1.360/Chromium 79.0.3945.130/支持H264/支持PDF预览 支持PDF预览和H264推荐版本 63/79/84/88/100/111/125 运行环境需要 visual c++ 2015不支持xp/vista/2003/2008默认不支持h264(版权问题)支持打印预览 print preview已知问题…

【计算机网络原理】GBN,SR,TCP区别以及案例介绍

概念介绍 GBN、SR和TCP协议的主要区别在于它们的重传机制、确认方式以及缓存机制的不同。‌ GBN&#xff08;Go-Back-N&#xff09;协议在数据传输中&#xff0c;如果某个报文段没有被正确接收&#xff0c;那么从这个报文段到后面的所有报文段都需要重新发送。GBN采用累计应答…

UI自动化测试 —— web端元素获取元素等待实践!

前言 Web UI自动化测试是一种软件测试方法&#xff0c;通过模拟用户行为&#xff0c;自动执行Web界面的各种操作&#xff0c;并验证操作结果是否符合预期&#xff0c;从而提高测试效率和准确性。 目的&#xff1a; 确保Web应用程序的界面在不同环境(如不同浏览器、操作系统)下…

每日OJ题_牛客_[NOIP2001]装箱问题_01背包_C++_Java

目录 牛客_[NOIP2001]装箱问题_01背包 题目解析 C代码 Java代码 牛客_[NOIP2001]装箱问题_01背包 [NOIP2001]装箱问题 (nowcoder.com) 描述&#xff1a; 有一个箱子容量为V&#xff08;正整数&#xff0c;0 ≤ V ≤ 20000&#xff09;&#xff0c;同时有n个物品&…

面向对象进阶(上)(JAVA笔记第二十二期)

p.s.这是萌新自己自学总结的笔记&#xff0c;如果想学习得更透彻的话还是请去看大佬的讲解 目录 static修饰符静态变量静态方法 工具类工具类的使用例子第一题第二题 static注意事项继承关系建立继承关系的格式继承的好处及使用场景继承的特点继承体系的设计继承中类的三大要素…

redis集群介绍

Redis集群是一种分布式存储系统&#xff0c;它通过将数据分散存储在多个Redis节点上来实现可扩展性和高可用性。每个节点都是一个独立的Redis服务器实例&#xff0c;它们通过网络相互连接&#xff0c;共同协作以提供数据服务。 在Redis集群中&#xff0c;数据被划分为多个槽&am…