【C++篇】STL适配器(上篇):栈与队列的底层(deque)奥秘

article/2025/7/5 18:58:03

💬 欢迎讨论:在阅读过程中有任何疑问,欢迎在评论区留言,我们一起交流学习!
👍 点赞、收藏与分享:如果你觉得这篇文章对你有帮助,记得点赞、收藏,并分享给更多对C++感兴趣的朋友


文章目录

    • 前言
      • 一、何为适配器?
      • 二、容器适配器
      • 三、stack的介绍和使用
        • 模拟实现stack
      • 四、queue的介绍和使用
        • 模拟实现queue
      • 五、deque双端队列
        • 1. deque的原理介绍
        • 2. deque的缺陷


前言

本文,我们接着学习STL的适配器。C++中的适配器主要分为三类:容器适配器迭代器适配器函数适配器

本阶段我们重点学习容器适配器和迭代器适配器。

适配器的内容我将分为两篇文章进行讲解,主要内容为:

  1. 上篇(本文):栈stack和队列queue
  2. 下篇:优先级队列priority_queue和反向迭代器reverse_iterator

本文目标

  • 了解什么是容器适配器
  • 学会使用stack、queue
  • 了解stack、queue的默认底层容器——deque
  • 能够模拟实现stack、queue

一、何为适配器?

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

在这里插入图片描述

核心思想

  • 复用:通过封装已有功能,避免重复实现

二、容器适配器

  • 基于现有容器(如 deque、list 或 vector)实现,提供特定的接口。

  • 常见的容器适配器:

    • stack后进先出(LIFO),默认基于 deque(也是一个容器,后文会讲解)。
    • 队列queue先进先出(FIFO),默认基于 deque。
    • 优先级队列priority_queue:优先级队列(),默认基于 vector。

三、stack的介绍和使用

在我们在学习初阶数据结构的时候已经掌握了stack和queue的物理和逻辑结构并用C语言模拟实现,若有遗忘,一定要及时复习:【初探数据结构】线性表——栈与队列(代码实现与详解)

在这里插入图片描述
在C++中,我们的STL库中已经有它们了,以后我们使用的时候直接调用接口即可,非常方便!终于不用再像C语言那样手搓一个栈了😭

接口记不住就查阅文档,用多了自然就记住了stack文档介绍

常用接口:

函数说明接口说明
stack()构造空的栈
empty()检测stack是否为空
size()返回stack中元素的个数
top()返回栈顶元素的引用
push()将元素val压入stack中
pop()将stack中尾部的元素弹出

看到这里可以去刷一些stack的题哦

模拟实现stack

我们先来凑一眼stl库的源代码

值的一提的是,很多小伙伴都说源代码看不懂,太晦涩了。其实我也看不懂(我是个小菜鸡😁),不必焦虑,我们仍在学习的过程中,我相信我们只要不断地坚持学习,看懂只是时间问题。

看不懂为什么还要看呢?
其实我们并不需要完全看懂,我们只需要提取关键信息(成员变量和成员函数),知道他在干什么就可以了。

#ifndef __SGI_STL_INTERNAL_STACK_H
#define __SGI_STL_INTERNAL_STACK_H__STL_BEGIN_NAMESPACE#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class T, class Sequence = deque<T> >
#else
template <class T, class Sequence>
#endif
class stack {friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference;
protected:Sequence c;
public:bool empty() const { return c.empty(); }size_type size() const { return c.size(); }reference top() { return c.back(); }const_reference top() const { return c.back(); }void push(const value_type& x) { c.push_back(x); }void pop() { c.pop_back(); }
};template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {return x.c == y.c;
}template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {return x.c < y.c;
}__STL_END_NAMESPACE

我们可以看到:

  • 他的模板信息:一个类型 + 一个容器(默认为deque)
  • 成员变量:一个容器对象
  • 成员函数实现方式:调用容器接口实现功能

有这些信息就够了,我们已经可以自己实现它们了!

#pragma once#include<iostream>
#include<deque>
#include<list>
#include<vector>using namespace std;namespace zhh
{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的介绍和使用

queue与stack的学习方式一样

queue文档介绍

在这里插入图片描述
常用接口:

函数声明接口说明
queue()构造空的队列
empty()检测队列是否为空,是返回true,否则返回false
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素val入队列
pop()将队头元素出队列
模拟实现queue

我们直接在stack代码的基础上改就可以了,控制尾进头出即可。
需要注意的是,pop必须调用pop_front(),那vector没有这个接口,是不是就不能适配了?没错,容器用vector会直接报错。
那为什么不用erase,这样就都适配了呀?
那我问你,vector头删的代价大不大?queue是不是只能用头删,是没有意义的。库中也是这样实现的。

#pragma once#include<iostream>
#include<deque>
#include<list>
#include<vector>using namespace std;namespace zhh
{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有何神通呢?

我们知道:

  • vector头插头删效率低,扩容还要更换空间
  • list迭代器不支持随机访问,空间不连续,CPU高速缓存效率不行

这些缺点,deque都弥补了。那为什么没有被广泛使用呢?

1. deque的原理介绍

deque(双端队列):是一种双开口的"连续"空间的数据结构
双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)。与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比
较高。
在这里插入图片描述

其实deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的。实际deque类似于一个动态的二维数组,由一个中控(指针数组)map,每个指针指向一块空间buff

底层结构如下图所示:
在这里插入图片描述

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

在这里插入图片描述

全貌:
在这里插入图片描述

2. deque的缺陷
  1. 相比于vector:
    • 随机访问的效率不及vector
  2. 相比于list:
    • 中间插入效率很低,只适合头和尾的修改

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

stack和queue需求只有头尾的修改,因此deque再适合不过了


完~


http://www.hkcw.cn/article/oGotMtoXlR.shtml

相关文章

leetcode刷题日记——二叉树的层次遍历

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; BFS&#xff0c;利用队列特性完成对树的层次遍历运行如下 int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {if (!root) {*returnSize 0;return NULL;}struct TreeNode* queue[2000];…

【优选算法 | 队列 BFS】构建搜索流程的核心思维

算法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;双指针滑动窗口二分查找前缀和位运算模拟链表哈希表字符串模拟栈模拟(非单调栈)优先级队列 很多人学 BFS 的时候都知道“用队列”&#xff0c;但为什么一定是队列&#xff1f;它到底在整个搜索流程中起了什么作…

Retrievers检索器+RAG文档助手项目实战

导读&#xff1a;作为企业级应用开发中的关键技术&#xff0c;LangChain检索器&#xff08;Retrievers&#xff09;正成为构建高效RAG系统的核心组件。本文将深入探讨检索器的技术架构与实战应用&#xff0c;帮助开发者掌握这一重要的AI工程技术。 检索器的价值在于提供统一的检…

word中如何快速调整全部表格大小

Step1: 选中一个表格&#xff0c;然后在自动调整选项卡中选择“根据窗口调整表格大小” Step2&#xff1a;选中其他表格 Step3: 按F4即可快速调整

设计模式——中介者设计模式(行为型)

摘要 文章详细介绍了中介者设计模式&#xff0c;这是一种行为型设计模式&#xff0c;通过中介者对象封装多个对象间的交互&#xff0c;降低系统耦合度。文中阐述了其核心角色、优缺点、适用场景&#xff0c;并通过类图、时序图、实现方式、实战示例等多方面进行讲解&#xff0…

20250602在荣品的PRO-RK3566开发板的Android13下的uboot启动阶段配置BOOTDELAY为10s

20250602在荣品的PRO-RK3566开发板的Android13下的uboot启动阶段配置BOOTDELAY为10s 2025/6/2 18:15 缘起&#xff1a;有些时候&#xff0c;需要在uboot阶段做一些事情。 于是&#xff0c;希望在荣品的PRO-RK3566开发板的Android13下的uboot启动停下。 1、【原始的LOG&#xff…

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战

汽车安全&#xff1a;功能安全&#xff08;FuSa&#xff09;、预期功能安全&#xff08;SOTIF&#xff09;与网络安全(Cybersecurity) 从理论到实战的安全体系 引言&#xff1a;自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进&#xff0c;汽车安全正从“机械可靠…

学习经验分享【40】目标检测热力图制作

目标检测热力图在学术论文&#xff08;尤其是计算机视觉、深度学习领域&#xff09;中是重要的可视化分析工具和论证辅助手段&#xff0c;可以给论文加分不少。主要作用一是增强论文的可解释性与说服力&#xff1a;论文中常需解释模型 “如何” 或 “为何” 检测到目标&#xf…

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)

给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性&#xff1a; 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意&#xff1a;直线的一般方程是 a*x b*y c 0&#xff0c;因此输入中只给出常数 a、b、…

判断用户输入昵称是否存在(Python)

一、运行结果 二、源代码 # 创建一个存储昵称的列表&#xff1b; name_list [章鱼, 张愚, 宇文弑]# 循环输入判断用户输入昵称是否存在 while True:# 获取用户输入的昵称&#xff1b;name input(请输入昵称&#xff1a;)# 判断昵称是否存在&#xff1b;if name in name_list…

RAG理论基础总结

目录 概念 流程 文档收集和切割 读取文档 转换文档 写入文档 向量转换和存储 搜索请求构建 向量存储工作原理 向量数据库 文档过滤和检索 检索前 检索 检索后 查询增强和关联 QuestionAnswerAdvisor查询增强 高级RAG架构 自纠错 RAG&#xff08;C-RAG&#xf…

pikachu靶场通关笔记09 XSS关卡05-DOM型XSS-X

目录 一、XSS 二、DOM型XSS 三、源码分析 1、打开DOM-X型XSS关卡 2、XSS探测 3、源码分析 四、渗透实战 1、Payload1 2、Payload2 3、Payload3 五、DOM型XSS与DOM-X型XSS区别 本系列为通过《pikachu靶场通关笔记》的XSS攻击关卡(共10关&#xff09;渗透集合&#xf…

3. TypeScript 中的数据类型

在 TypeScript 中&#xff0c;类型&#xff08;Types&#xff09;允许你定义并强制执行应用中数据的结构。通过使用类型&#xff0c;你可以在编译阶段捕捉错误&#xff0c;而不是等到运行时才发现&#xff0c;从而让代码更加可预测&#xff0c;也更不容易出现 bug。TypeScript …

【Java Web】速通Tomcat

参考笔记:JavaWeb 速通Tomcat_tomcat部署java项目-CSDN博客 目录 一、Tomcat服务 1. 下载和安装 2. 启动Tomcat服务 3. 启动Tomcat服务的注意事项 4. 关闭Tomcat服务 二、Tomcat的目录结构 1. bin 🌟 2. conf 🌟 3. lib 4. logs 5. temp 6. webapps 7. work 三、Web项目…

从零实现Python扫雷游戏:完整开发指南与深度解析

目录 一、游戏架构设计 1.1 核心组件 1.2 类结构设计 二、核心算法实现 2.1 地雷生成算法 2.2 数字计算算法 2.3 空白区域展开算法 三、图形界面开发 3.1 主界面布局 3.2 交互事件处理 左键点击事件 右键点击事件 3.3 游戏状态显示 四、游戏功能扩展 4.1 多难度…

hooks组件-useState

hooks组件-useState hook组件的本质就是函数组件&#xff0c;但是基于各种hook让其动态化&#xff01; 常用hook&#xff1a; useReducer&#xff1a;redux useCallback useMemo&#xff1a;去做一些优化。 useRef&#xff1a;使用ref useImperativeHandle&#xff1a;拿到子组…

X浏览器APP:轻巧快捷,畅享极速浏览

在移动互联网时代&#xff0c;浏览器作为我们获取信息、娱乐和社交的重要工具&#xff0c;其性能和功能直接影响着我们的使用体验。X浏览器APP正是这样一款专为移动设备设计的轻巧快捷的网络浏览器&#xff0c;它凭借独特的核心引擎和多项实用功能&#xff0c;为用户提供了极速…

一种基于性能建模的HADOOP配置调优策略

1.摘要 作为分布式系统基础架构的Hadoop为应用程序提供了一组稳定可靠的接口。该文作者提出了一种基于集成学习建模的Hadoop配置参数调优的方法。实验结果表明&#xff0c;该性能模型可以准确预测MapReduce应用程序的运行时间。采用提出的Hadoop配置参数方法调优后&#xff0c…

【001】利用github搭建静态网站_essay

文章目录 1. 简介2. 先了解网址规则2.1 文件及网址形式2.2 相互访问 3. 搭建网页的过程3.1 网页文件3.2 github搭建仓库及文件上传3.3 搭建网站 1. 简介 相信大家都有过想要自己搭建一个稳定可靠的网站&#xff0c;github是一个不错的选择&#xff0c;本来国内有gitee可以搭建…

太极APP:免Root,畅享Xposed模块的神奇魅力

在安卓系统中&#xff0c;Xposed框架一直以其强大的功能和高度的自定义能力受到众多用户的喜爱。然而&#xff0c;传统的Xposed框架需要Root权限和复杂的刷机操作&#xff0c;这使得许多普通用户望而却步。太极APP的出现&#xff0c;打破了这一限制&#xff0c;它为用户提供了一…