当前位置: 首页 > news >正文

【C++】stack 和 queue 的适配器模式与实现

 
> 🍃 本系列为初阶C++的内容,如果感兴趣,欢迎订阅🚩
> 🎊个人主页:[小编的个人主页])小编的个人主页
>  🎀   🎉欢迎大家点赞👍收藏⭐文章
> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍


目录

 

 🐼前言

 🐼栈和队列的认识和使用 

  🐼栈和队列的模拟实现

 🐼适配器

  🐼stack的模拟实现

  🐼queue的模拟实现 

  🐼总结 


 🐼前言

 在C语言中,不管是实现一个栈还是实现队列,我们都需要从底层开始造轮子😩;在C++中,我们一直强调不暴露底层结构,讲究提供一组特定的接口,来隐藏容器的底层实现细节,从而实现特定的数据结构行为。我们能否提供一种高效、灵活且易于扩展的方式来实现栈和队列,同时也保持了代码的简洁性和可维护性的方式😜

 🐼栈和队列的认识和使用 

我们可以借助Cplusplus来查看<stack>和<queue>类的一些常用接口(类中的其它接口小伙伴们可以根据我给的链接在需要时进行查询)。 

🌻<stack>的一些常见接口

🌻<queue>的一些常见接口

  1. empty:检测队列是否为空 
  2. size:返回队列中有效元素的个数
  3. front:返回队头元素的引用
  4. back:返回队尾元素的引用
  5. push_back:在队列尾部入队列
  6. pop_front:在队列头部出队列

🍁我们发现,栈和队列的接口基本一样。他们之间的区别是栈遵循后进先出原则,栈顶入数据且出数据,而队列讲究先进先出原则,队尾入数据,队头出数据

正是因为栈和队列只能在数据的一端进行操作,增加了限制,才诞生了两个这样独一无二的数据结构。好比程序员的“叠叠乐”与“排队游戏

  🐼栈和队列的模拟实现

🍁在C语言中,我们实现栈时,最优是底层使用的是一片连续空间的数组。而实现队列,最优我们使用链表来封装。而现在,我们已经有了<vector>和<list>容器,栈和队列无非就是在<vector>和<list>中对一端进行操作限制我们能否想到一种方式,借助已有的类/容器,来帮助我们完成所需的类

答案是可以的采用适配器的方式。在C++ STL中,<stack>和<queue>就是适配器的典型应用。它们通过封装一个底层容器(如<vector>或<deque(双端队列)),并提供栈或队列的接口,从而隐藏了底层容器的具体实现

 🐼适配器

🌈在上一节,我们在list的反向迭代器中提到了适配器的概念,使用正向迭代器来适配出反向迭代器。这一节我们再理解适配器这个概念。

适配器模式是一种结构型设计模式,它允许将一个类的接口转换为另一个接口,就像我们的手机充电器一样适配器模式的核心是通过封装一个已有的类(或对象),并提供一个新的接口,进行类之间的复用,使得原本不兼容的接口能够协同工作

🍁由于栈和队列本质上是对容器的一种特殊操作限制

  • 栈(Stack)后进先出(LIFO),只允许在容器的一端进行插入和删除操作。

  • 队列(Queue)先进先出(FIFO),只允许在一端插入,在另一端删除。

🔍因此通过适配器模式,std::stackstd::queue封装了一个底层容器(如std::vectorstd::dequestd::list),并限制了对容器的操作,从而实现栈和队列的行为。

本质上还是对类的复用,我们只关注接口操作,比如std::stack只暴露了push()pop()top()empty()等接口,用户无法直接访问底层容器的其他操作。这种封装保证了数据结构的正确性和安全性,我们也只关注push()pop()top()empty(),不需要了解底层push()是如何实现的

下面我们通过实现来感受适配器的魅力!

  🐼stack的模拟实现

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

🍁由于<stack>和<list>没有遍历操作,没有迭代器,这时,我们使用双端队列来完成尾部头部操作效率很高,因此,我们采用双端队列<deque>作为默认的适配器,如果显示传,也可以传<vector>,<list>作为适配器。

🔍对于双端队列,小伙伴们可以自行去了解,这里知道

双端队列支持 push_front(头部插入)、push_back(尾部插入)、pop_front(头部删除)、pop_back(尾部删除)等操作效率很高,都为O(1)

✅代码解析:

具体实现操作即栈在只允许在栈顶一端操作,对适配器数据一端比如<vector>做限制即可,调用<vector>类的接口

  🐼queue的模拟实现 

#pragma once
#include"stack.h"
namespace lsg
{template<class T,class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}T& front(){return _con.front();}T& back(){return _con.back();}//只读const T& front()const{return _con.front();}const T& back()const{return _con.back();}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}private:Container _con;};
}

✅代码解析:

我们仅需要完成队列的接口,实现我们想要的接口。用适配器适配出队列。而适配器底层是如何实现的,不需要我们关心。这里适配器不能用<vector>,因为<vector>不支持头删操作,效率太低。这里标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

为什么选择deque作为stack和queue的底层默认容器?

🔍stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如 list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为: 1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进 行操作。 2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据)queue中的元素增长时,deque不仅效率高,而且内存使用率高。 结合了deque的优点,而完美的避开了其缺陷。不过在有些场景,比如说容器如果牵扯遍历,deque就显得很不足了。

  🐼总结 

⌛️通过适配器模式,C++ STL提供了一种高效、灵活且易于扩展的方式来实现栈和队列,同时也保持了代码的简洁性和可维护性。让底层隐藏实现细节,只暴露特定的接口。

通过适配器,支持我们可以自定义容器。甚至我们可以自定义底层容器,甚至可以实现自己的容器类,只要满足适配器的要求。这正是C++设计STL的强大之处。也实现了数据结构的行为(栈或队列)与底层容器的实现解耦。实现了低耦合,高内聚的思想。

 感谢你耐心地阅读到这里,你的支持是我不断前行的最大动力。如果你觉得这篇文章对你有所启发,哪怕只是一点点,那就请不吝点赞👍,收藏⭐️,关注🚩吧!你的每一个点赞都是对我最大的鼓励,每一次收藏都是对我努力的认可,每一次关注都是对我持续创作的鞭策。希望我的文字能为你带来更多的价值,也希望我们能在这个充满知识与灵感的旅程中,共同成长,一起进步。再次感谢你的陪伴,期待与你在未来的文章中再次相遇!⛅️🌈 ☀️   

相关文章:

【C++】stack 和 queue 的适配器模式与实现

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…...

【python】You-Get

文章目录 1、介绍2、安装与使用文档3、下载图片4、下载视频5、下载音乐6、参考 1、介绍 You-Get is a tiny command-line utility to download media contents (videos, audios, images) from the Web, in case there is no other handy way to do it. 源码&#xff1a;https…...

PHP基础部分

但凡是和输入、写入相关的一定要预防别人植入恶意代码! HTML部分 语句格式 <br> <hr> 分割符 <p>插入一行 按住shift 输入! 然后按回车可快速输入html代码(VsCode需要先安装live server插件) html:<h1>标题 数字越大越往后</h1> <p…...

gitee SSH 公钥设置教程

Gitee 提供了基于 SSH 协议的 Git 服务,在使用 SSH 协议访问仓库仓库之前,需要先配置好账户 SSH 公钥。 1、生成秘钥 Windows 用户建议使用 Windows PowerShell 或者 Git Bash,在 命令提示符 下无 cat 和 ls 命令。 ssh-keygen -t ed25519 -C "Gitee SSH Key"中间…...

Java零基础入门笔记:(3)程序控制

前言 本笔记是学习狂神的java教程&#xff0c;建议配合视频&#xff0c;学习体验更佳。 【狂神说Java】Java零基础学习视频通俗易懂_哔哩哔哩_bilibili Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互&#xff0c;但是Java给我们提供了这样一个工具类&…...

鸡兔同笼问题

鸡兔同笼问题是这样一个问题&#xff1a; 现有鸡、兔合装在一个笼子里。数头一共100个头&#xff0c;数脚一共300只脚。问有多少只鸡多少只兔&#xff1f; 在这里讨论这个问题的解法当然太小儿科了。但是y_tab这个C语言解释器只提供了1维数组。如果需要用到2维数组时&#xff…...

【Pytorch 库】自定义数据集相关的类

torch.utils.data.Dataset 类torch.utils.data.DataLoader 类自定义数据集示例1. 自定义 Dataset 类2. 在其他 .py 文件中引用和使用该自定义 Dataset torch_geometric.data.Dataset 类torch_geometric.data.Dataset VS torch.utils.data.Dataset 详细信息&#xff0c;参阅 tor…...

electron打包基本教程

从0开始搭建 概要步骤基础软件运行项目打包项目 注意事项 概要 将html打包成桌面的主流有electron和nwjs&#xff0c;nwjs更加简单&#xff0c;但是使用效果不如electron&#xff0c;electron打包比较麻烦&#xff0c;但是效果比较好&#xff0c;反正各有优势和缺点 步骤 基…...

实现pytorch注意力机制-one demo

主要组成部分&#xff1a; 1. 定义注意力层&#xff1a; 定义一个Attention_Layer类&#xff0c;接受两个参数&#xff1a;hidden_dim&#xff08;隐藏层维度&#xff09;和is_bi_rnn&#xff08;是否是双向RNN&#xff09;。 2. 定义前向传播&#xff1a; 定义了注意力层的…...

深入Flask:如何优雅地处理HTTP请求与响应

哈喽,大家好,我是木头左! 本文将带你深入了解如何在Flask中优雅地处理HTTP请求和响应,让你的应用更加高效、安全和用户友好。 创建一个简单的Flask应用 让从创建一个最简单的Flask应用开始: from flask import Flaskapp = Flask(__name__)@app.route(/) def...

JVM ②-双亲委派模型 || 垃圾回收GC

这里是Themberfue 在上节课对内存区域划分以及类加载的过程有了简单的了解后&#xff0c;我们再了解其他两个较为重要的机制&#xff0c;这些都是面试中常考的知识点&#xff0c;有必要的话建议背出来&#xff0c;当然不是死记硬背&#xff0c;而是要有理解的背~~~如果对 JVM …...

jQuery介绍(快速、简洁JavaScript库,诞生于2006年,主要目标是简化HTML文档操作、事件处理、动画和Ajax交互)

文章目录 **核心功能 & 亮点**1. **简化 DOM 操作**2. **链式调用**3. **跨浏览器兼容**4. **便捷的事件绑定**5. **Ajax 封装**6. **动画效果** **现状与适用场景**- **传统项目维护**&#xff1a;许多旧系统&#xff08;如 WordPress 插件、老企业网站&#xff09;仍依赖…...

python旅游推荐系统+爬虫+可视化(协同过滤算法)

✅️基于用户的协同过滤算法 ✅️有后台管理 ✅️2w多数据集 这个旅游数据分析推荐系统采用了Python语言、Django框架、MySQL数据库、requests库进行网络爬虫开发、机器学习中的协同过滤算法、ECharts数据可视化技术&#xff0c;以实现从网站抓取旅游数据、个性化推荐和直观展…...

Ubuntu 22.04.5 LTS 安装企业微信,(2025-02-17安装可行)

一、依赖包(Ubuntu 20.04/Debian 11) 点击下载https://www.spark-app.store/download_dependencies_latest 1、 下载最新的依赖包。 请访问星火应用商店依赖包下载页面, 下载最新的依赖包。2、解压依赖包 </...

【Excel笔记_6】条件格式和自定义格式设置表中数值超过100保留1位,超过1000保留0位,低于100为默认

方法一&#xff1a;自定义格式 选中需要设置格式的单元格区域。右键选择设置单元格格式&#xff0c;或者在工具栏中选择开始 -> 数字 -> 自定义格式。在类型框中输入以下自定义格式&#xff1a; [>1000]0;[>100]0.0;G/通用格式解释&#xff1a; [>1000]0&…...

UDP与TCP

用UDP一定比用TCP快吗&#xff1f; 假设我们需要在a电脑的进程发一段数据到b电脑的进程我们可以选择使用TCP或UDP协议进行通信。 对于TCP这样的可靠性协议每次消息发出后都能明确知道对方有没有收到&#xff0c;就像打电话一样&#xff0c;只要“喂喂"两下对方就能回你个…...

Web开发技术概述

Web开发技术涵盖了前端和后端开发&#xff0c;以及数据库技术。前端开发包括使用HTML、CSS、JavaScript等原生技术&#xff0c;以及jQuery、Bootstrap、AngularJS、React、Vue等框架。后端开发则涉及ASP.NET、PHP、Python Web&#xff08;Flask、Django&#xff09;、Java Web&…...

解压rar格式的软件有哪些?8种方法(Win/Mac/手机/网页端)

RAR 文件是一种常见的压缩文件格式&#xff0c;由尤金・罗谢尔&#xff08;Eugene Roshal&#xff09;开发&#xff0c;因其扩展名 “rar” 而得名。它通过特定算法将一个或多个文件、文件夹进行压缩&#xff0c;大幅减小存储空间&#xff0c;方便数据传输与备份。然而&#xf…...

uniapp开发:首次进入 App 弹出隐私协议窗口

前言&#xff1a;在移动应用开发中&#xff0c;隐私协议弹窗是一个非常重要的功能。它不仅符合法律法规的要求&#xff08;如 GDPR、CCPA 等&#xff09;&#xff0c;还能增强用户对 App 的信任感。本文将介绍如何在 Uniapp 开发的 App 中实现“首次进入弹出隐私协议窗口&#…...

执行pnpm run dev报错:node:events:491 throw er; // Unhandled ‘error‘ event的解决方案

vite搭建的vue项目&#xff0c;使用pnpm包管理工具&#xff0c;执行pnpm run dev&#xff0c;报如下错误&#xff1a; 报错原因&#xff1a; pnpm依赖安装不完整&#xff0c;缺少esbuild.exe文件&#xff0c;导致无法执行启动命令。 解决方案&#xff1a; 根据错误提示中提到…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...