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

深入探讨【C++容器适配器】:现代编程中的【Stack与Queue】的实现

目录

一、Stack(栈)

1.1 Stack的介绍

1.2 Stack的使用

1.3 Stack的模拟实现

二、Queue(队列)

2.1 Queue的介绍

2.2 Queue的使用

2.3 Queue的模拟实现

三、容器适配器

3.1 什么是适配器

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

​编辑

总结


 

专栏:C++学习笔记 

上一卷:C++—list容器

在C++中,stackqueue是两种非常重要的数据结构,广泛应用于各种算法和系统中。本文将详细介绍这两种数据结构的基本概念、使用方法及其底层实现,并结合代码示例和运行结果进行详细讲解。

一、Stack(栈)

1.1 Stack的介绍

stack(栈)是一种容器适配器,专门用于后进先出(LIFO, Last In First Out)的操作环境中。栈的元素插入和删除操作只能在容器的一端进行,即栈顶。

栈的底层容器可以是任何标准的容器类模板或一些其他特定的容器类,这些容器类应支持以下操作:

  • empty(): 判空操作
  • back(): 获取尾部元素操作
  • push_back(): 尾部插入元素操作
  • pop_back(): 尾部删除元素操作

标准容器vectordequelist均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque

小李的理解:
栈就像是一叠盘子,你只能从顶部添加或移除盘子。这就意味着最后添加的盘子最先被移除(后进先出)。在C++中,栈的底层可以用多种容器实现,但一般默认用deque,因为它支持高效的尾部操作。

1.2 Stack的使用

stack的常用操作包括:

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

示例代码

#include <stack>
#include <iostream>int main() {std::stack<int> s;s.push(1);s.push(2);s.push(3);std::cout << "Stack top: " << s.top() << std::endl; // 输出3s.pop();std::cout << "Stack top after pop: " << s.top() << std::endl; // 输出2return 0;
}

首先我们压入了三个元素1, 2, 3,栈顶元素是3。然后我们弹出了栈顶元素,栈顶变成了2。

小李的理解:
就像把三个盘子按顺序叠起来(1在最底下,3在最上面)。当我们移走最上面的盘子时,下面的盘子就成了新的顶部。

1.3 Stack的模拟实现

从栈的接口中可以看出,栈实际是一种特殊的vector,因此使用vector完全可以模拟实现stack

示例代码

#include <vector>
#include <iostream>namespace bite {template<class T>class stack {public:stack() {}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:std::vector<T> _c;};
}int main() {bite::stack<int> s;s.push(1);s.push(2);s.push(3);std::cout << "Custom stack top: " << s.top() << std::endl; // 输出3s.pop();std::cout << "Custom stack top after pop: " << s.top() << std::endl; // 输出2return 0;
}

这表明我们的自定义stack实现与标准库中的行为一致。

小李的理解:
我们自己实现了一个简单的栈,用vector来存储元素。每次添加元素时,将它们推到vector的尾部;每次移除元素时,从vector的尾部移除。这和我们平时用的栈行为完全一样。

二、Queue(队列)

2.1 Queue的介绍

queue(队列)是一种容器适配器,专门用于先进先出(FIFO, First In First Out)的操作环境中。队列的元素插入操作在容器的一端进行,即队尾,而提取操作在容器的另一端进行,即队头。

队列的底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。这些容器类应支持以下操作:

  • empty(): 检测队列是否为空
  • size(): 返回队列中有效元素的个数
  • front(): 返回队头元素的引用
  • back(): 返回队尾元素的引用
  • push_back(): 在队列尾部插入元素
  • pop_front(): 在队列头部删除元素

标准容器dequelist满足这些要求。默认情况下,如果没有为queue指定特定的底层容器,则使用deque

小李的理解:
队列就像排队买票,最早来的人最先买到票(先进先出)。在C++中,队列的底层可以用多种容器实现,但一般默认用deque,因为它支持高效的头尾操作。

2.2 Queue的使用

queue的常用操作包括:

  • queue(): 构造空的队列
  • empty(): 检测队列是否为空
  • size(): 返回队列中有效元素的个数
  • front(): 返回队头元素的引用
  • back(): 返回队尾元素的引用
  • push(val): 在队尾将元素val入队列
  • pop(): 将队头元素出队列

示例代码

#include <queue>
#include <iostream>int main() {std::queue<int> q;q.push(1);q.push(2);q.push(3);std::cout << "Queue front: " << q.front() << std::endl; // 输出1q.pop();std::cout << "Queue front after pop: " << q.front() << std::endl; // 输出2return 0;
}

首先我们压入了三个元素1, 2, 3,队头元素是1。然后我们弹出了队头元素,队头变成了2。

小李的理解:
就像排队买票,第一个人买了票离开,第二个人就成了最前面的人。

2.3 Queue的模拟实现

因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list来模拟实现queue

示例代码

#include <list>
#include <iostream>namespace bite {template<class T>class queue {public:queue() {}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:std::list<T> _c;};
}int main() {bite::queue<int> q;q.push(1);q.push(2);q.push(3);std::cout << "Custom queue front: " << q.front() << std::endl; // 输出1q.pop();std::cout << "Custom queue front after pop: " << q.front() << std::endl; // 输出2return 0;
}

 

这表明我们的自定义queue实现与标准库中的行为一致。

小李的理解:
我们自己实现了一个简单的队列,用list来存储元素。每次添加元素时,将它们推到list的尾部;每次移除元素时,从list的头部移除。这和我们平时用的队列行为完全一样。

三、容器适配器

3.1 什么是适配器

适配器是一种设计模式,该模式是将一个类的接口转换成客户希望的另外一个接口。在STL中,stackqueue就是通过适配器模式将dequevector等容器类的接口转换成特定的LIFO或FIFO操作。

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

虽然stackqueue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stackqueue只是对其他容器的接口进行了包装,STL中stackqueue默认使用deque。主要原因如下:

  1. stackqueue不需要遍历(因此stackqueue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. stack中元素增长时,dequevector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

结合了deque的优点,而完美地避开了其缺陷,使其成为stackqueue的理想底层容器。

总结

C++中的stackqueue通过容器适配器实现,分别用于LIFO和FIFO操作。stackqueue的底层容器默认使用deque,但也可以根据需求选择其他标准容器。理解并灵活运用这些数据结构,对于高效编写算法和处理复杂数据具有重要意义。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • SpringBoot使用RedisTemplate、StringRedisTemplate操作Redis
  • 如何使一个盒子水平垂直居中(常用的)
  • C++:类和对象 I(访问限定符、this指针)
  • 租用海外服务器需要考虑哪些因素
  • STM32入门开发操作记录(一)——新建工程
  • “好物”推荐+Xshell连接实例+使用Conda创建独立的Python环境
  • 通过git将文件push到github 远程仓库
  • windows信息收集和提权
  • jitsi 使用JWT验证用户身份
  • AI克隆声音,基于函数计算部署GPT-Sovits语音生成模型
  • 亚马逊erp有店铺不知道怎么上传产品的看过来!
  • shell从入门到精通(只需要这篇就够了)
  • 本地部署 EVE: Unveiling Encoder-Free Vision-Language Models
  • 前端部署自动上传资源文件到cdn/oss 解决路由和访问慢的问题
  • Hadoop3:HDFS-通过配置黑白名单对集群进行扩缩容,并实现数据均衡(实用)
  • 0基础学习移动端适配
  • Android Volley源码解析
  • ComponentOne 2017 V2版本正式发布
  • ECMAScript6(0):ES6简明参考手册
  • HTML5新特性总结
  • Linux Process Manage
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • PHP 小技巧
  • Swoft 源码剖析 - 代码自动更新机制
  • 初识 beanstalkd
  • 高度不固定时垂直居中
  • 那些被忽略的 JavaScript 数组方法细节
  • 前端面试题总结
  • 前言-如何学习区块链
  • 物联网链路协议
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 小而合理的前端理论:rscss和rsjs
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​ubuntu下安装kvm虚拟机
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #pragma 指令
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • (java)关于Thread的挂起和恢复
  • (八十八)VFL语言初步 - 实现布局
  • (分布式缓存)Redis分片集群
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (十六)视图变换 正交投影 透视投影
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)人的集合论——移山之道
  • (转载)从 Java 代码到 Java 堆
  • ***利用Ms05002溢出找“肉鸡
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .htaccess 强制https 单独排除某个目录
  • .NET Core WebAPI中封装Swagger配置
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .net中调用windows performance记录性能信息