【C++】stack queue

stack & queue

  • 一、容器适配器
  • 二、deque(了解)
  • 三、stack
    • 1. stack 的介绍
    • 2. 模拟实现 stack
  • 四、queue
    • 1. queue 的使用
    • 2. 模拟实现 queue
    • 3. priority_queue
      • (1)priority_queue 的介绍
      • (2)priority_queue 的使用
      • (3)仿函数
      • (4)模拟实现 priority_queue

一、容器适配器

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

虽然 stackqueue 中也可以存放元素,但在 STL 中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为 stackqueue 只是对其他容器的接口进行了包装,STLstackqueue 默认使用 deque(后面介绍), 比如:

在这里插入图片描述

在这里插入图片描述

其实容器适配器就是复用其他容器,利用其他容器的功能来适配出一个新的容器。

二、deque(了解)

deque(双端队列): 是一种双开口的 “连续” 空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为 O(1),与 vector 比较,头插效率高,不需要搬移元素;与 list 比较,空间利用率比较高。如果需要高效的随机存取,还要大量的首尾的插入删除则建议使用 deque.

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

在这里插入图片描述

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

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

但是,deque 有一个致命缺陷:不适合遍历,因为在遍历时,deque 的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑 vectorlistdeque 的应用并不多,而目前能看到的一个应用就是,STL 用其作为 stackqueue 的底层数据结构。

那么为什么选择 deque 作为 stackqueue 的底层默认容器呢?

stack 是一种后进先出的特殊线性数据结构,因此只要具有push_back()pop_back() 操作的线性结构,都可以作为 stack 的底层容器,比如 vectorlist 都可以;

queue先进先出的特殊线性数据结构,只要具有 push_backpop_front 操作的线性结构,都可以作为 queue 的底层容器,比如 list。但是 STL 中对 stackqueue 默认选择 deque 作为其底层容器,主要是因为:

  1. stackqueue 不需要遍历 (因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. stack 中元素增长时,dequevector 的效率高(扩容时不需要搬移大量数据);queue 中的元素增长时,deque 不仅效率高,而且内存使用率高。结合了 deque 的优点,而完美的避开了其缺陷。

三、stack

1. stack 的介绍

我们先可以看一下 stack 的文档介绍:stack.

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

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

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

     		empty:判空操作back:获取尾部元素操作push_back:尾部插入元素操作pop_back:尾部删除元素操作
    
  4. 标准容器 vector、deque、list 均符合这些需求,默认情况下,如果没有为 stack 指定特定的底层容器,默认情况下使用 deque.

我们先简单地看看 stack 的使用:

		void test_stack(){stack<int> st;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);while (!st.empty()){cout << st.top() << ' ';st.pop();}cout << endl;}

运行结果如下:

在这里插入图片描述

2. 模拟实现 stack

我们使用 deque 作为 stack 的适配器模拟实现:

		#pragma once#include <vector>#include <deque>namespace Young{template <class T, class Container = deque<T>>class Stack{public:// 入栈void push(const T& val){_con.push_back(val);}// 出栈void pop(){_con.pop_back();}// 获取栈顶元素T& top(){return _con.back();}// const 对象获取栈顶元素const T& top() const{return _con.back();}// 获取栈的大小size_t size(){return _con.size();}// 判断栈是否为空bool empty(){return _con.empty();}private:Container _con;};}

如上,stack 的常用接口就实现好了,我们再用我们自己实现的 stack 测试一下:

在这里插入图片描述

四、queue

1. queue 的使用

我们先看一下 queue 的文档介绍:queue.

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

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

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

     		empty:检测队列是否为空size: 返回队列中有效元素的个数front:返回队头元素的引用back: 返回队尾元素的引用push_back:在队列尾部入队列pop_front:在队列头部出队列
    
  4. 标准容器类 dequelist 满足了这些要求。默认情况下,如果没有为 queue 实例化指定容器类,则使用标准容器 deque.

先简单看一下 queue 的使用:

		void test_queue(){queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);while (!q.empty()){cout << q.front() << ' ';q.pop();}cout << endl;}

运行结果如下:

在这里插入图片描述

2. 模拟实现 queue

我们也使用 deque 适配 queue

		#pragma once#include <deque>namespace Young{template<class T, class Container = deque<T>>class Queue{public:// 入队列void push(const T& val){_con.push_back(val);}// 出队列void pop(){_con.pop_front();}// const 对象获取队头元素const T& front() const{return _con.front();}// 获取队头元素T& front(){return _con.front();}// const 对象获取队尾元素const T& back() const{return _con.back();}// 获取队尾元素T& back(){return _con.back();}// 获取队列长度size_t size(){return _con.size();}// 判断队列是否空bool empty(){return _con.empty();}private:Container _con;};}

我们再使用自己实现的 queue,来测试一下:

在这里插入图片描述

3. priority_queue

(1)priority_queue 的介绍

priority_queue:优先级队列,是属于队列的一种,我们先看一下它的文档介绍 priority_queue.

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

  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先级队列中位于顶部的元素)。

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

     		empty():检测容器是否为空size(): 返回容器中有效元素个数front():返回容器中第一个元素的引用push_back():在容器尾部插入元素pop_back(): 删除容器尾部元素
    
  4. 标准容器类 vectordeque 满足这些需求。默认情况下,如果没有为特定的 priority_queue 类实例化指定容器类,则使用vector

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

(2)priority_queue 的使用

优先级队列默认使用 vector 作为其底层存储数据的容器,在 vector 上又使用了堆算法vector 中元素构造成堆的结构,因此 priority_queue 就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下 priority_queue大堆

在这里插入图片描述

注意,我们看文档,默认情况下 priority_queue大堆,但是上图中红框中的是一个仿函数(后面介绍),就是实现比较的,其中 less 有小的意思,但是它却实现成大堆,这里要注意。其次,我们使用默认的参数时,只需要传第一个参数即可,后面的使用缺省参数即可,但是我们需要使用小堆的时候就需要将全部参数都传进去;我们先来看看使用:

		#include <vector>#include <queue>#include <functional> // greater算法的头文件void TestPriorityQueue(){// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成 greater 比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;}

运行结果如下:

在这里插入图片描述

(3)仿函数

仿函数又称为函数对象,是一个能行使函数功能的类。它的使用和我们平时的函数调用一样。

首先我们得先实现一个类,这个类中需要实现 () 运算符重载,里面实现的功能需要我们自己实现,假设我们需要实现 priority_queue 中的大堆,如下:

		// 仿函数 --- 大堆,大的优先级大template <class T>class Less{public:bool operator()(const T& x, const T& y){return x < y;}};

那么如何调用呢?首先我们得先创建一个对象,再使用这个对象进行调用函数:

			Less<int> less;cout << less(1, 8) << endl; // 与下等价cout << less.operator()(1, 8) << endl;

运行结果如下:

在这里插入图片描述

下面我们使用仿函数的形式模拟实现 priority_queue.

(4)模拟实现 priority_queue

	#pragma once#include <vector>namespace Young{// 模板参数template <class T, class Container = vector<T>, class Compare = Less<T>>class PriorityQueue{public:// 向上调整 --- 大堆void adjust_up(size_t child){Compare com;size_t parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child]) // 与下等价if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}// 向下调整 --- 大堆void adjust_down(size_t parent){Compare com;size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child + 1] > _con[child]){++child;}// if (_con[parent] < _con[child])  // 与下等价if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}// 入数据void push(const T& val){_con.push_back(val);adjust_up(_con.size() - 1);}// 出数据void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}// 获取优先级最大的数据const T& top(){return _con.front();}// 判空bool empty(){return _con.empty();}private:Container _con;};}

下面我们使用自己实现的优先级队列进行测试:

		void test_priority_queue(){// Young::PriorityQueue<int, vector<int>, Greater<int>> pq; // 小堆// Young::PriorityQueue<int, vector<int>, Less<int>> pq; // 大堆,与下等价Young::PriorityQueue<int> pq;  // 缺省参数默认是大堆pq.push(2);pq.push(8);pq.push(1);pq.push(0);pq.push(10);while (!pq.empty()){cout << pq.top() << ' ';pq.pop();}cout << endl;}

测试结果如下:

在这里插入图片描述

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

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

相关文章

[Linux]多线程编程

[Linux]多线程编程 文章目录 [Linux]多线程编程pthread_create函数pthread_join函数pthread_exit函数pthread_cancel函数pthread_self函数pthread_detach函数理解线程库和线程id Linux操作系统下&#xff0c;并没有真正意义上的线程&#xff0c;而是由进程中的轻量级进程&#…

Python二级 每周练习题20

练习一: 日期计算器 设计一款日期计算程序&#xff0c;能否实现下面的功能&#xff1a; (1)要求用户分别输入年、月、日&#xff08;分三次输入&#xff09;&#xff1b; (2)程序自动会根据输入的年月日计算出这一天是这一年的第几天&#xff1b; (3)输出格式为&#xff1a;这…

超全超详细的Redis笔记-数据类型及其使用、主从复制、哨兵模式、缓存穿透、击穿、雪崩

文章目录 狂神聊Redis1、Nosql概述1.1、为什么要用Nosql1.2、什么是NoSQL1.3、NoSQL的四大分类 2、Redis 入门2.1、概述2.2、Windows 安装2.3、Linux安装2.4、测试性能2.5、Redis基础知识 3、五大基本数据类型3.1、Redis-Key3.2、String3.3、List3.4、Set3.5、Hash&#xff08;…

SpringMVC基础

MVC详细解释如下&#xff1a; M是指业务模型&#xff08;Model&#xff09;&#xff1a;通俗的讲就是我们之前用于封装数据传递的实体类。 V是指用户界面&#xff08;View&#xff09;&#xff1a;一般指的是前端页面。 C则是控制器&#xff08;Controller&#xff09;&#…

【Python】Python 使用copy模块深拷贝对象

Python 使用copy模块深拷贝对象 浅拷W和深拷贝的概念&#xff1a; 浅拷贝&#xff08;shallow copy ):构造一个新的复合对象并将从原对象中发现的引用插人该对象 中。浅拷贝的实现方式有多种&#xff0c;如工厂函数数、切片操作、copy模块中WCoPy操作等。 深拷贝&#xff08…

成都瀚网科技有限公司:抖店精选联盟怎么用?

抖音精选联盟是抖音电商平台提供的一项服务&#xff0c;旨在为商家提供更多的推广机会和销售渠道。然而&#xff0c;很多人对于如何使用抖店精选联盟以及如何开通这项服务不太了解。本文将为您详细介绍抖店精选联盟的使用和激活流程。 第一节&#xff1a;如何使用抖店精选联盟 …

Spring DI (Dependency Injection)

What Is DI? 当一个类需要依赖另一个对象&#xff0c;把另一个对象实例化之后注入给这个对象的过程我们称之为DI # Create an object dependency in traditional programming public class Store {private Item item;public Store() {item new ItemImpl1(); } }# Using …

美丽塔O(n)解法单调栈

题目 见上一篇&#xff1a; 较难算法美丽塔时间复杂度O(n)-CSDN博客 时间复杂度 O(n) 分析 接着上篇。从左向右依次处理Left&#xff0c;处理Left[i]时&#xff0c;从右向左寻找第一个符合maxHeights[j]<maxHeights[i]的j。如果j1<j2&#xff0c;且maxHeights[j1]&g…

国密国际SSL双证书解决方案,满足企事业单位国产国密SSL证书要求

近年来&#xff0c;为了摆脱对国外技术和产品的依赖&#xff0c;建设安全的网络环境&#xff0c;以及加强我国对网络信息的安全可控能力&#xff0c;我国推出了国密算法。同时&#xff0c;为保护网络通信信息安全&#xff0c;更高级别的安全加密数字证书—国密SSL证书应运而生。…

容器管理工具 Docker生态架构及部署

目录 一、Docker生态架构 1.1 Docker Containers Are Everywhere 1.2 生态架构 1.2.1 Docker Host 1.2.2 Docker daemon 1.2.3 Registry 1.2.4 Docker client 1.2.5 Image 1.2.6 Container 1.2.7 Docker Dashboard 1.3 Docker版本 二、Docker部署 2.1 使用YUM源部署…

用友U8 CRM客户关系管理任意文件上传漏洞复现【附POC】

文章目录 用友U8 CRM客户关系管理任意文件上传漏洞复现0x01 前言0x02 漏洞描述0x03 影响平台0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现4.访问shell地址 0x06 整改建议 用友U8 CRM客户关系管理任意文件上传漏洞复现 0x01 前言 免责声明&#xff1a;请勿利用文…

【Java 基础篇】Java网络编程实战:P2P文件共享详解

Java网络编程是现代软件开发中不可或缺的一部分&#xff0c;因为它允许不同计算机之间的数据传输和通信。在本篇博客中&#xff0c;我们将深入探讨Java中的P2P文件共享&#xff0c;包括什么是P2P文件共享、如何实现它以及一些相关的重要概念。 什么是P2P文件共享&#xff1f; …

蓝牙核心规范(V5.4)10.7-BLE 入门笔记之L2CAP

1.概述 ATT属性用于两个设备,一个扮演客户端的角色,另一个扮演服务器的角色。服务器公开一系列称为属性的复合数据项。这些属性由服务器按索引列表组织在称为属性表的列表中。 每个属性包含一个句柄、一个通用唯一标识符(UUID)、一个值和一组权限。 句柄是一个唯一的索引…

mysql自动删除过期的binlog

一、binlog_expire_logs_seconds 配置项 mysql 8.0使用配置项 binlog_expire_logs_seconds 设置binlog过期时间&#xff0c;单位为秒。 mysql旧版本使用配置项 expire_logs_days 设置binlog过期时间&#xff0c;单位为天&#xff0c;不方便测试。 在 8.0 使用 expire_logs_d…

蓝牙核心规范(V5.4)11.4-LE Audio 笔记之音频模型

专栏汇总网址:蓝牙篇之蓝牙核心规范学习笔记(V5.4)汇总_蓝牙核心规范中文版_心跳包的博客-CSDN博客 爬虫网站无德,任何非CSDN看到的这篇文章都是盗版网站,你也看不全。认准原始网址。!!! 从一开始,蓝牙低功耗(Bluetooth Low Energy,BLE)音频的开发就秉持着“以设…

外包干了3个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;大专生&#xff0c;17年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

Lua函数

--函数--无参无返回值 function F1()print("F1函数") end F1() print("*****************")--有参 function F2(a)print("F2函数"..a) end F2(2) --如果传入参数和函数数量不一致 --不会报错只是补空 F2(1,2) print("*****************&quo…

Wireshark抓包分析ICMP协议

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 分析目的&#xff1a;分析ICMP协议的数据格式、报文…

机器人过程自动化(RPA)入门 4. 数据处理

到目前为止,我们已经了解了RPA的基本知识,以及如何使用流程图或序列来组织工作流中的步骤。我们现在了解了UiPath组件,并对UiPath Studio有了全面的了解。我们用几个简单的例子制作了我们的第一个机器人。在我们继续之前,我们应该了解UiPath中的变量和数据操作。它与其他编…

【免费】2023云栖大会门票开抢啦!数量有限,先到先得!

&#x1f3ab; 报名方式&#xff1a;点击链接即可免费报名&#xff01; &#x1f517; 2023云栖大会-领票页 &#x1f4c5; 10月31日-11月2日&#xff0c;让我们齐聚云栖小镇&#xff01;