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

STL详解 - stack与queue的模拟实现

目录

一、容器适配器

1. 什么是适配器模式

2. stack与queue的底层结构

3. deque的原理与缺陷

3.1 deque的原理

3.2 deque的缺陷 

4. 为何选择deque作为默认底层容器

二、stack与queue的模拟实现

1. stack的实现

2. queue的实现


一、容器适配器

1. 什么是适配器模式

        适配器模式是一种结构型设计模式,其核心思想是将一个类的接口转换为用户期望的另一个接口。在STL中,容器适配器(如stackqueue)通过封装现有容器(如dequevectorlist),提供符合特定数据结构特性的接口,从而屏蔽底层细节,简化开发。


2. stack与queue的底层结构

尽管stackqueue可以存储元素,但它们并非直接归类为容器,而是容器适配器。这是因为它们基于其他容器进行接口封装,默认情况下使用deque作为底层容器:


3. deque的原理与缺陷

3.1 deque的原理

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

deque并不是真正连续的空间,其内部由多个固定大小的连续内存块(缓冲区) 组成,通过中控器(指针数组)管理这些块,形成一个逻辑上的连续空间。实际deque类似于一个动态的二维数组,其底层结构如下图所示:

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


 

那deque是如何借助迭代器维护其假想连续的结构呢? 

3.2 deque的缺陷 

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

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

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


4. 为何选择deque作为默认底层容器

尽管deque有遍历效率低的缺陷,但作为stackqueue的底层容器却十分合适:

  1. 无需遍历stackqueue仅需在固定端操作,规避了deque的遍历缺陷。

  2. 高效扩容:相比vectordeque扩容时无需搬移大量元素。

  3. 内存友好:相比listdeque内存碎片少,空间利用率高。


二、stack与queue的模拟实现

1. stack的实现

  • stack 使用 deque 作为底层容器,默认通过模板参数指定。

  • push pop 操作分别调用底层容器的 push_back pop_back

  • top 方法返回栈顶元素,直接调用底层容器的 back 方法。

  • size empty 方法分别返回底层容器的大小和是否为空。

#include <deque>namespace lv
{template <class T, class Container = std::deque<T>>class stack{public:// 构造函数stack(){}// 向栈顶添加元素void push(const T& x){_container.push_back(x); // 使用底层容器的 push_back}// 从栈顶移除元素void pop(){_container.pop_back(); // 使用底层容器的 pop_back}// 获取栈顶元素T& top(){return _container.back(); // 使用底层容器的 back}// 获取栈顶元素(const版本)const T& top() const{return _container.back();}// 获取栈的大小size_t size() const{return _container.size();}// 判断栈是否为空bool empty() const{return _container.empty();}private:Container _container; // 底层容器,默认使用 deque};
}

2. queue的实现

  • queue 使用 deque 作为底层容器,默认通过模板参数指定。

  • push 方法调用底层容器的 push_back,将元素添加到队尾。

  • pop 方法调用底层容器的 pop_front,从队头移除元素。

  • front back 方法分别返回队头和队尾的元素。

  • sizeempty 方法分别返回底层容器的大小和是否为空。

#include <deque>namespace lv 
{template <class T, class Container = std::deque<T>>class queue {public:// 构造函数queue() {}// 向队尾添加元素void push(const T& x) {_container.push_back(x); // 使用底层容器的 push_back}// 从队头移除元素void pop() {_container.pop_front(); // 使用底层容器的 pop_front}// 获取队头元素T& front() {return _container.front(); // 使用底层容器的 front}// 获取队头元素(const版本)const T& front() const {return _container.front();}// 获取队尾元素T& back() {return _container.back(); // 使用底层容器的 back}// 获取队尾元素(const版本)const T& back() const {return _container.back();}// 获取队列的大小size_t size() const {return _container.size();}// 判断队列是否为空bool empty() const {return _container.empty();}private:Container _container; // 底层容器,默认使用 deque};
}

相关文章:

  • 《AI大模型应知应会100篇》第22篇:系统提示词(System Prompt)设计与优化
  • USART讲解
  • 深入理解类:ArkTS面向对象编程的核心概念
  • 批量操作的优点
  • idea mvn执行打包命令后控制台乱码
  • 【无标题】STM32CubeMX
  • 【SpringBoot+Vue自学笔记】003 SpringBoot Controll
  • Oracle DBMS_SCHEDULER 与 DBMS_JOB 的对比
  • 【音视频开发】第五章 FFmpeg基础
  • k8s调度器:如何控制Pod的分布
  • 【Android】 如何将 APK 内置为系统应用(适用于编辑设置属性)
  • vim编辑器
  • Android Compose Activity 页面跳转动画详解
  • 更换 CentOS 7.9 的系统源
  • 智能交响:EtherCAT转Profinet网关开启汽车自动化通信新纪元
  • Linux电源管理(三),CPUIdle 和 ARM的PSCI
  • VFlash的自动化和自定义动作
  • 深入理解Qt状态机的应用
  • C++23 新特性:std::size_t 字面量后缀 Z/z
  • B3634 最大公约数和最小公倍数
  • 2人恶意传播刘国梁谣言被处罚,媒体:以法律利剑劈谣斩邪,加快推进依法治体
  • 下辖各区密集“联手”,南京在下一盘什么样的棋?
  • 《五行令》《攻守占》,2个月后国博见
  • 美联储计划裁员约10%
  • 马上评|训斥打骂女儿致死,无暴力应是“管教”底线
  • 商务部召开全国离境退税工作推进会:提高退税商店覆盖面,扩大入境消费