【C++】栈、队列、双端队列与优先级队列

目录

一、stack(栈)

二、queue(队列)

三、deque(双端队列)

(一)概念

(二)为什么能作为 stack 和 queue 的容器

(三)缺点

四、priority_queue(优先级队列)

(一)概念

(二)仿函数

(三)模拟实现优先级队列


        vector、list 是容器,而 stack 与 queue 是容器适配器。

        所谓的容器适配器,其实就是在容器的基础上进行封装,得到我们的目标结构。

        如图所示,vector 和 queue的第二个模板参数便是封装的容器,我们可以看到默认的容器是deque,我们也可以选择 vector 或者 list 。这种设计模式被称为适配器模式。

        C语言版本实现:数据结构——栈与队列-CSDN博客

一、stack(栈)

        栈的特点是后进先出,同时不提供迭代器。

        下面是模拟实现:

#pragma once
#include <iostream>
#include<deque>
using namespace std;
namespace mh
{template<class T, class Con = deque<T>>class stack{public:void push(const T& x){_c.push_back(x);}void pop(){_c.pop_back();}T& top(){return _c.back();}const T& top()const{return _c.back();}size_t size()const{return _c.size();}bool empty()const{return _c.empty();}private:Con _c;};
}

二、queue(队列)

        队列的特点是先进先出,同时不提供迭代器。

        下面是模拟实现:

#pragma once
#include <iostream>
#include<deque>
using namespace std;
namespace mh
{template<class T, class Con = deque<T>>class queue{public:void push(const T& x){_c.push_back(x);}void pop(){_c.pop_front();}T& back(){return _c, back();}const T& back()const{return _c.back();}T& front(){return _c.front();}const T& front()const{return _c.front();}size_t size()const{return _c.size();}bool empty()const{return _c.empty();}private:Con _c;};
}

三、deque(双端队列)

(一)概念

        deque是具有动态大小的顺序容器,可以在两端扩展或收缩。

                               

(二)为什么能作为 stack 和 queue 的容器

        deque不仅支持 [ ] 访问元素,而且头尾插入删除效率非常高。对于 stack 和 queue这两种结构只能在头或者尾进行操作,因此 deque 非常契合需求。

        栈的持续插入元素时,vector的扩容需要挪动数据,而deque扩容时并不需要对原生数据进行挪动,只需增加中控数组和段空间的映射关系并在段空请插入元素即可。队列的元素增长时,deque效率高,同时因为存在部分连续存储,所以三级缓存命中率及空间利用率比list高。

(三)缺点

        随机访问速度不如vector。由于deque的中控数组中指向的一段段地址空间之间并不连续,所以随机访问时需要计算目标数据处于哪个中控指针指向的空间的第几个元素。计算方式与磁盘定位扇区类似(LBA地址转化为CHS地址)。所以deque的随机访问速度并没有vector快。

        中间插入、删除速度不如list。从deque的底层结构图中可以看出,中间插入、删除数据仍会产生数据的挪动且挪动复杂。deque中间插入、删除数据的速度不如list。

四、priority_queue(优先级队列)

(一)概念

        优先级队列是一种容器适配器不提供迭代器,它的底层是一个堆(默认是大堆),这个堆默认使用vector进行适配。

        其中第一个模板参数表明优先级队列存储元素的类型,第二个函数参数表明封装的容器类型,而第三个模板参数是仿函数,默认调用库里的 less ,默认生成大根堆。

priority_queue<int, vector<int>, less<int>> pq;      //大堆
priority_queue<int, vector<int>, greater<int>> pq;   //小堆

(二)仿函数

        仿函数是一种行为类似于函数的对象,它通过重载圆括号操作符“()`”来实现类似函数的调用方式。

namespace mh
{template<class T>class less {public:bool operator()(const T& x, const T& y)const{return x < y;}};template<class T>class greater {public:bool operator()(const T& x, const T& y)const{return x > y;}};
}int main()
{mh::less<int> comp;if (comp(1, 2))cout << "1 < 2" << endl;elsecout << " 1 >= 2" << endl;return 0;
}

(三)模拟实现优先级队列

namespace mh
{template<class T>class less {public:bool operator()(const T& x, const T& y)const{return x < y;}};template<class T>class greater {public:bool operator()(const T& x, const T& y)const{return x > y;}};template <class T, class Container = vector<T>, class Compare = less<T>>class priority_queue{private:Container c;Compare comp;void adjust_up(size_t child){size_t parent = (child - 1) / 2;while (child > 0){if (comp(c[parent], c[child])){swap(c[parent], c[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjust_down(size_t parent){size_t child = parent * 2 + 1;while (child < c.size()){if (child + 1 < c.size() && comp(c[child], c[child + 1])){++child;}if (comp(c[parent], c[child])){swap(c[parent], c[child]);parent = child;child = parent * 2 + 1;}else{break;}}}public:priority_queue(){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last):c(first, last){for (size_t i = (c.size() - 1 - 1) / 2; i > 0; --i){adjust_down(i);}}bool empty() const{return c.empty();}size_t size() const{return c.size();}const T& top()const {return c.front();}void push(const T& x){c.push_back(x);adjust_up(c.size() - 1);}void pop(){swap(c[0], c[c.size() - 1]);c.pop_back();adjust_down(0);}};
};

        当我们队内元素是指针类型时,对于自定义仿函数,我们可以使用函数重载进行指定类型的处理,也可以使用模板特化进行指针类型的处理。

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

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

相关文章

02 —— Webpack 修改入口和出口

概念 | webpack 中文文档 | webpack中文文档 | webpack中文网 修改入口 webpack.config.js &#xff08;放在项目根目录下&#xff09; module.exports {//entry设置入口起点的文件路径entry: ./path/to/my/entry/file.js, }; 修改出口 webpack.config.js const path r…

实验室管理现代化:Spring Boot技术方案

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

深入探讨 Puppeteer 如何使用 X 和 Y 坐标实现鼠标移动

背景介绍 现代爬虫技术中&#xff0c;模拟人类行为已成为绕过反爬虫系统的关键策略之一。无论是模拟用户点击、滚动&#xff0c;还是鼠标的轨迹移动&#xff0c;都可以为爬虫脚本带来更高的“伪装性”。在众多的自动化工具中&#xff0c;Puppeteer作为一个无头浏览器控制库&am…

【软考】系统架构设计师-计算机系统基础(4):计算机网络

计算机网络功能&#xff1a;数据通信、资源共享、管理集中化、分布式处理、负载均衡 5G高峰速率&#xff1a;10Gbit/s 广域网&#xff08;因特网&#xff09;/城域网/局域网&#xff08;以太网&#xff09; 总线型&#xff1a;利用率低&#xff0c;易冲突&#xff0c;干扰大…

【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

240.搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 先动手写写最简单方法&#xff0c;二重循环。 class Solution { public:bool searchMa…

从技术到产品:第三方美颜API助力实时直播平台的开发详解

众所周知&#xff0c;开发一套完整的美颜功能不仅耗时耗力&#xff0c;还需要大量的算法调优与硬件优化。为此&#xff0c;第三方美颜API成为越来越多开发者的优先选择。本篇文章&#xff0c;小编将从技术到产品&#xff0c;深入探讨第三方美颜API如何助力直播平台的快速开发。…

《深入理解 Spring MVC 工作流程》

一、Spring MVC 架构概述 Spring MVC 是一个基于 Java 的轻量级 Web 应用框架&#xff0c;它遵循了经典的 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;将请求、响应和业务逻辑分离&#xff0c;从而构建出灵活可维护的 Web 应用程序。 在 Spring MV…

大数据新视界 -- 大数据大厂之 Impala 性能优化:融合人工智能预测的资源预分配秘籍(上)(29 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【MySQL-3】表的约束

目录 1. 整体学习的思维导图 2. 非空约束 3. default约束 4. No Null和default约束 5. 列描述 comment 6. Zerofill 7. 主键 primary key 复合主键 8. 自增长 auto_increment 9. 唯一键 10. 外键 11. 实现综合案例 1. 整体学习的思维导图 2. 非空约束 正如该标题一…

【Linux】Namespace

一、概念 Linux Namespace 是 Linux 内核提供的一种特性&#xff0c;用于对系统资源进行隔离。通过 Namespace&#xff0c;不同的进程组可以拥有独立的系统资源视图&#xff0c;即使它们在同一台物理机器上运行。这种隔离机制使得容器技术成为可能&#xff0c;因为它允许在单个…

在MATLAB中实现自适应滤波算法

自适应滤波算法是一种根据信号特性自动调整滤波参数的数字信号处理方法&#xff0c;其可以有效处理噪声干扰和信号畸变问题。在许多实时数据处理系统中&#xff0c;自适应滤波算法得到了广泛应用。在MATLAB中&#xff0c;可以使用多种方法实现自适应滤波算法。本文将介绍自适应…

Python学习------第十天

数据容器-----元组 定义格式&#xff0c;特点&#xff0c;相关操作 元组一旦定义&#xff0c;就无法修改 元组内只有一个数据&#xff0c;后面必须加逗号 """ #元组 (1,"hello",True) #定义元组 t1 (1,"hello") t2 () t3 tuple() prin…

软件测试—— Selenium 常用函数(一)

前一篇文章&#xff1a;软件测试 —— 自动化基础-CSDN博客 目录 前言 一、窗口 1.屏幕截图 2.切换窗口 3.窗口设置大小 4.关闭窗口 二、等待 1.等待意义 2.强制等待 3.隐式等待 4.显式等待 总结 前言 在前一篇文章中&#xff0c;我们介绍了自动化的一些基础知识&a…

Rust 力扣 - 746. 使用最小花费爬楼梯

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用a&#xff0c;b分别记录n - 2层向上爬的最小花费&#xff0c;n - 1层向上爬的最小花费 到达楼梯顶第N层&#xff0c;只能从N - 1层或者N - 2层向上爬 所以爬到第N层的最小花费 第N - 1层向上爬和第N - …

VRT: 关于视频修复的模型

VRT: 关于视频修复的模型 1. 视频修复的背景与重要性背景介绍&#xff1a;重要性&#xff1a; 2. VRT的重要性和研究背景VRT的背景&#xff1a;VRT的重要性&#xff1a; 3. 视频修复概述3.1 定义与目标3.2 与单图像修复的区别3.3 对时间信息利用的需求 4. VRT模型详解4.1 整体框…

关于C++地址交换的实现

关于地址的交换实现&#xff0c;我们要使用指针引用的方式进行&#xff0c;例如&#xff1a; #include <iostream>// 定义函数交换两个整型指针的地址 void swapIntPtrAddresses(int* &ptr1, int* &ptr2) {int *temp ptr1;ptr1 ptr2;ptr2 temp; }int main() …

HarmonyOS ArkUI(基于ArkTS) 常用组件

一 Button 按钮 Button是按钮组件&#xff0c;通常用于响应用户的点击操作,可以加子组件 Button(我是button)Button(){Text(我是button)}type 按钮类型 Button有三种可选类型&#xff0c;分别为胶囊类型&#xff08;Capsule&#xff09;、圆形按钮&#xff08;Circle&#xf…

SpringBoot学习笔记(一)

一、Spring Boot概述 &#xff08;一&#xff09;微服务概述 1、微服务 微服务&#xff08;英语&#xff1a;Microservices&#xff09;是一种软件架构风格&#xff0c;它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础&#xff0c;利用模块化的方式…

C++初阶(十三)--STL--vector的使用

目录 ​编辑 一、vector的基本介绍 二、vector的使用 1.构造函数的介绍 2.容量操作 size和capacity reserve和resize empty 3.vector的遍历 operator[ ](size_t n) 迭代器使用 begin和end rbegin和rend 4.vector的增删查改 push_back和pop_back insert和erase fi…

用Python爬虫“偷窥”1688商品详情:一场数据的奇妙冒险

引言&#xff1a;数据的宝藏 在这个信息爆炸的时代&#xff0c;数据就像是一座座等待挖掘的宝藏。而对于我们这些电商界的探险家来说&#xff0c;1688上的商品详情就是那些闪闪发光的金子。今天&#xff0c;我们将化身为数据的海盗&#xff0c;用Python这把锋利的剑&#xff0…