C++ : STL容器(适配器)之stack、queue剖析

STL容器适配器之stack、queue剖析
- 一、stack、queue的接口
- (一)stack 接口说明
- (二)queue 接口说明
- 二、stack、queue的模拟实现
- (一)stack、queue是容器适配器
- stack、queue底层默认容器--deque
- 1、deque概念及原理
- 2、stl中deque迭代器的实现(部分)
- (二)stack的模拟实现
- (三)queue的模拟实现
- 三、优先队列
- (一)优先队列的概念
- (二)优先队列的接口说明
- (三)优先队列的模拟实现
- 四、结束语
一、stack、queue的接口
(一)stack 接口说明
- stack()
- 构造空的栈
- empty()
- 检测stack是否为空
- size()
- 返回stack中元素的个数
- top()
- 返回栈顶元素的引用
- push()
- 将元素val压入stack中
- pop()
- 将stack中尾部的元素弹出
(二)queue 接口说明
- empty:
- 检测队列是否为空
- size:
- 返回队列中有效元素的个数
- front:
- 返回队头元素的引用
- back:
- 返回队尾元素的引用
- push_back:
- 在队列尾部入队列
- pop_front:
- 在队列头部出队列
二、stack、queue的模拟实现
(一)stack、queue是容器适配器
虽然
stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque.
stack、queue底层默认容器–deque
1、deque概念及原理
deque(双端队列):可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个
动态的二维数组,其底层结构如下图所示:
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问
的假象,落在了deque的迭代器身上
2、stl中deque迭代器的实现(部分)

在stl源码实现中,下面截取了迭代器的部分,有很多知识值得学习。
1、普通迭代器和
const迭代器实现技巧我们知道
const对象的实现就是不能修改值,因此只需要在实现迭代器时针对一下->和*的返回值即可,源码库中使用两个模板参数巧妙的解决这个问题。
2、非类型模板参数
在模板进阶中我们会讲到非类型模板参数的使用,使用
size_t作为参数相当于一个宏的使用。
template <class T, class Ref, class Ptr, size_t BufSiz>
3、重载的复用
先实现重载符号 += 接着的 +、-、-=都采用了复用的方式,使得代码更简洁。
在实现++、–时,先实现前置++,前置–,再实现后置++,后置–,这里也可以复用
#pragma once
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {typedef __deque_iterator<T, T&, T*, BufSiz> iterator;typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef T** map_pointer;typedef ptrdiff_t difference_type;typedef __deque_iterator self;//构造函数//有参构造__deque_iterator(T* x, map_pointer y): cur(x), first(*y), last(*y + buffer_size()), node(y) {}//默认构造__deque_iterator() : cur(0), first(0), last(0), node(0) {}//拷贝构造__deque_iterator(const iterator& x): cur(x.cur), first(x.first), last(x.last), node(x.node) {}//更新结点信息void set_node(map_pointer new_node) {node = new_node;first = *new_node;last = first + difference_type(buffer_size());}//运算符重载reference operator*() const { return *cur; }pointer operator->() const { return &(operator*()); }self& operator++() {++cur;if (cur == last) {set_node(node + 1);cur = first;}return *this;}self operator++(int) {self tmp = *this;++*this;return tmp;}self& operator--() {if (cur == first) {set_node(node - 1);cur = last;}--cur;return *this;}self operator--(int) {self tmp = *this;--*this;return tmp;}self& operator+=(difference_type n) {difference_type offset = n + (cur - first);if (offset >= 0 && offset < difference_type(buffer_size()))cur += n;else {difference_type node_offset =offset > 0 ? offset / difference_type(buffer_size()): -difference_type((-offset - 1) / buffer_size()) - 1;set_node(node + node_offset);cur = first + (offset - node_offset * difference_type(buffer_size()));}return *this;}self operator+(difference_type n) const {self tmp = *this;return tmp += n;}self& operator-=(difference_type n) { return *this += -n; }self operator-(difference_type n) const {self tmp = *this;return tmp -= n;}reference operator[](difference_type n) const { return *(*this + n); }bool operator==(const self& x) const { return cur == x.cur; }bool operator!=(const self& x) const { return !(*this == x); }bool operator<(const self& x) const {return (node == x.node) ? (cur < x.cur) : (node < x.node);}//成员变量
private:T* cur;T* first;T* last;map_pointer node;
};
(二)stack的模拟实现
通过
stack的实现可以看出,stack的实现是基于deque。栈的实现就是将双端队列进行包装,这个过程就像是deque是交流电,而stack就是这个插头,为用户提供需要的接口。
#pragma once
#include<vector>
#include<list>
#include<deque>
using namespace std;namespace wgm {template<class T, class Container = deque<T>>class stack {public:void push(const T& val) {_con.push_back(val);}void pop() {_con.pop_back();}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}const T& top() const{return _con.back();}private:Container _con;};
}
(三)queue的模拟实现
和
stack类似,在它的参数列表中也有一个参数类型Container(容器),它也存在默认参数deque。这里的参数不能传入vector,因为vector不支持头部出元素的pop_front操作。
#pragma once
#include<vector>
#include<list>
#include<deque>
using namespace std;namespace wgm {template<class T, class Container = deque<T>>class queue {public:void push(const T& val) {_con.push_back(val);}void pop() {_con.pop_front();}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();}private:Container _con;};
}
三、优先队列
(一)优先队列的概念
优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大(小)的。实际上,这就和之前学过的数据结构堆的性质一样。
(二)优先队列的接口说明
- empty():
- 检测容器是否为空
- size():
- 返回容器中有效元素个数
- front():
- 返回容器中第一个元素的引用
- push_back():
- 在容器尾部插入元素
- pop_back():
- 删除容器尾部元素
(三)优先队列的模拟实现
#pragma once
#include<vector>
#include<iostream>
using namespace std;namespace wgm {template <class T>struct less{bool operator() (const T& x, const T& y) const{return x < y;}};template <class T>struct greater{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 {public:
#define FATHER(i) (((i) - 1) / 2)
#define LEFT(i) (((i) * 2) + 1)
#define RIGHT(i) (((i) * 2) + 2)void AdjustUp(int i){Compare cmp;while (FATHER(i) >= 0 && Compare()(_con[FATHER(i)], _con[i])) {swap(_con[i], _con[FATHER(i)]);i = FATHER(i);}}void AdjustDown(int i){while (LEFT(i) < _con.size()) {int l = LEFT(i), r = RIGHT(i), ind = i;Compare cmp;if (cmp(_con[ind], _con[LEFT(i)])) ind = LEFT(i);if (RIGHT(i) < _con.size() && cmp(_con[ind], _con[RIGHT(i)])) ind = RIGHT(i);if (ind == i) break;swap(_con[i], _con[ind]);i = ind;}}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}bool empty(){return _con.empty();}const T& top(){return _con[0];}size_t size(){return _con.size();}private:Container _con;};
}
四、结束语
这个部分相对于之前学的容器要简单,只不过这个双端队列的实现源码还是挺有意思的,可以尝时着实现实现。
相关文章:
C++ : STL容器(适配器)之stack、queue剖析
STL容器适配器之stack、queue剖析 一、stack、queue的接口(一)stack 接口说明(二)queue 接口说明 二、stack、queue的模拟实现(一)stack、queue是容器适配器stack、queue底层默认容器--deque1、deque概念及…...
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
按照pinia官网步骤安装运送服务会报一个500[vite-node] [ERR_LOAD_URL]问题,查阅各个网站资料没有找到有用信息. 最后解决:在package.json中把pinia的版本给降回0.5.5版本之后就正常了 "dependencies": {"element-plus/icons-vue": "^2.3.1",&q…...
青少年编程能力等级测评CPA试卷(2)Python编程(一级)
青少年编程能力等级测评CPA试卷(2) Python编程(一级) (考试时间90分钟,满分100分) 一、单项选择题(共20题,每题3.5分,共70分) 下列语句的输出结果是( &am…...
wordpress判断page页与非page页
在WordPress中,你可以使用is_page()函数来判断当前页面是否为page类型。以下是如何使用这个函数的示例: <?php if (is_page()) {// 当前页面是page类型echo 这是一个Page页面; } else {// 当前页面不是page类型echo 这不是一个Page页面; } ?> …...
JavaScript 库-qs的使用
meta.query qs.parse(query)语句解析:qs.parse(query) qs 是一个常用的 JavaScript 库(全称为 query-string 或 qs),它用于处理 URL 查询字符串。qs.parse(query) 会将查询字符串解析成一个对象。举个例子: 假设有一…...
Leetcode 两数之和 Ⅱ - 输入有序数组
这段代码实现了在一个非递减排序的数组中找到两个数,使它们的和等于目标值的算法。算法使用了双指针技术,具体思想如下: 算法思想: 初始化指针:定义两个指针 left 和 right,分别指向数组的起始位置和末尾位…...
多处理器一致协议(MSI)协议详细介绍
多处理器一致协议 MSI 协议详细介绍 #mermaid-svg-2lc6AxM2mRiND4C0 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-2lc6AxM2mRiND4C0 .error-icon{fill:#552222;}#mermaid-svg-2lc6AxM2mRiND4C0 .error-text{fill:…...
SSH实验5密钥登录Linuxroot用户(免密登录)
当用户尝试通过SSH连接到远程服务器时,客户端会生成一对密钥:公钥和私钥。公钥被发送到远程服务器,并存储在服务器的~/.ssh/authorized_keys文件中。而私钥则由客户端保管,不会传输给服务器。 在连接过程中,客户端使用…...
2024 网鼎杯 - 青龙组 Web WP
2024 网鼎杯 - 青龙组 WEB - 02 打开容器一个登录界面,随便输入账号密码可以进到漏洞界面 这里有一个发送给boss的功能,一眼xss 有三个接口:/flag 、/update 、/submit /flag :要求boss才能访问,/update …...
ORACLE 闪回技术简介
闪回技术是若干技术的集合 包含对数据库整体的闪回 对表的闪回 对事务的闪回 经典面试题面试题:简述Oracle数据库闪回技术? 1.闪回Oracle数据库 2.闪回表 3.闪回事务 数据库闪回 要想实现数据库闪回 1.必须配置数据库的恢复区 SQL> show parameter …...
【笔记】LLC电路工作频点选择 2-2 开关管与滤波压力
LLC谐振变换器稳态工作波形分析 - 知乎,上面这篇文的结论相较MPS那篇文章的结论更严格。我们分析一下它的频点选择为什么会更窄: 1. LLC电路模型 电流滞后的特性就是电路呈感性注意这里也是开关管ZVS开通。 2.工作循环的波形 iLm的波形,最终…...
【CUDA】认识CUDA
目录 一、CUDA编程 二、第一个CUDA程序 三、CUDA关键字 四、device管理 4.1 初始化 4.2 Runtime API查询GPU信息 4.3 决定最佳GPU CUDA C 编程指南CUDA C在线文档:CUDA C 编程指南 CUDA是并行计算的平台和类C编程模型,能很容易的实现并行算法。只…...
Linux(CentOS)yum update -y 事故
CentOS版本:CentOS 7 事情经过: 1、安装好CentOS 7,系统自带JDK8,版本为:1.8.0_181 2、安装好JDK17,版本为:17.0.13 3、为了安装MySQL执行了 yum update -y(这个时候不知道该命令的…...
AI绘画赚钱秘籍!掌握ai绘画赚钱技巧,开启副业新篇章,ai绘画赚钱实战指南!
AI绘画赚钱:方法与策略 一、引言 随着人工智能技术的日益发展,AI绘画作为新兴领域,正逐渐成为赚钱的新途径。本文将从多个角度探讨AI绘画赚钱的完整策略,帮助读者深入了解并把握这一领域的商机。 二、AI绘画赚钱的主要方式…...
HCIP-HarmonyOS Application Developer V1.0 笔记(四)
平板/折叠屏设计 自适应动态布局:相对拉伸、相对缩放、延伸布局 响应式动态布局:挪移布局、重复布局、瀑布布局 Sketch 插件 设计系统:提供了 HarmonyOS 设计语言中定义的视觉参数和设计资源文件。 控件库:按类别组织控件&…...
【前端】Svelte:组件封装与使用
在 Svelte 中,组件化是开发的核心理念。将页面的不同部分封装成独立组件,不仅可以提升代码的复用性,还能让项目的结构更加清晰。在本文中,我们将介绍如何创建、封装、引入和使用 Svelte 组件,帮助你快速上手 Svelte 的…...
STM32标准库-待机模式
1.1 STM32待机模式简介 STM32单片机具有低功耗模式,包括睡眠、停止和待机三种。 运行状态下,HCLK为CPU提供时钟。HCLK由AHB预分频器分频后直接输出得到。 低功耗模式选择需考虑电源消耗、启动时间和唤醒源。 睡眠模式停CPU不停外设时钟; 停止…...
【论文笔记】The Power of Scale for Parameter-Efficient Prompt Tuning
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: The Power of Scale for P…...
几个docker可用的镜像源
几个docker可用的镜像源 💐The Begin💐点点关注,收藏不迷路💐 sudo rm -rf /etc/docker/daemon.json sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://d…...
Spring学习笔记_27——@EnableLoadTimeWeaving
EnableLoadTimeWeaving 1. 介绍 在Spring框架中,EnableLoadTimeWeaving 是一个注解,它用于启用加载时织入(Load-Time Weaving, LTW) LWT[Spring学习笔记_26——LWT-CSDN博客] 2. 场景 AOP:在Spring框架中…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

