【C++杂货铺】详解 stack 和 queue

2024-04-10 06:04
文章标签 c++ 详解 stack queue 杂货铺

本文主要是介绍【C++杂货铺】详解 stack 和 queue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


🌈前言🌈

        欢迎收看本期【C++杂货铺】,本期内容将讲解C++STL中stack和queue的内容,其中包含了stack , queue,priority_queue是什么,怎么使用以及模拟实现这些容器。

        此外,还将将讲解设计模式中的适配器模式,以及STL中stack,queue的底层deque。

📁 stack 介绍和使用

 📂 介绍

        stack是一种容器适配器,专门用于具有先进后出的上下文环境,只能从容器的一端进行元素的插入和提取操作。

        stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层,元素特定容器的尾部被压入和弹出。

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

        ● empty : 判空操作。

        ● back:获取尾部元素操作。

        ● push_back:尾部插入元素操作。

        ● pop_back:尾部删除元素操作。

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

📂 使用

stack - C++ Reference (cplusplus.com)

#include <iostream>
#include <stack>using namespace std;int main()
{stack<int> st;st.push(1);st.push(2);st.push(3);while(!st.empty()){cout<<st.top()<<" ";st.pop();    }cout<<endl;
}

 📂 模拟实现

#include<deque>
namespace exercise
{template<class T, class Con = deque<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:Con _c;};
}

📁 queue 介绍和使用

 📂 介绍

        队列也是一种容器适配器,专门用于先进先出的操作,其中从容器一端插入元素,另一端提取元素。

        队列作为容器适配器实现,容器适配器将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素,元素从队尾入队列,从队头出队列。

        底层容器可以是变化尊模板容器类模板之一,也可以是其他专门设计的容器类,该底层容器应该支持一下操作:

        ● empty : 检测队列是否为空。

        ● size : 返回队列中有效元素的个数。

        ● front : 返回队头元素的引用。

        ● back:返回队尾元素的引用。

        ● push_back:在队列尾部入队列。

        ● pop_back:在队列头部出队列。

        标准容器类deque和list满足这些要求,默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

 📂 使用

queue - C++ Reference (cplusplus.com)

#include <iostream>
#include <queue>using namespace std;int main()
{queue<int> q;q.push(1);q.push(2);q.push(3);while(!q.empty()){cout<<q.front()<<" ";q.pop();}cout<<endl;return 0;
}

 📂 模拟实现

#include <deque>
#include <list>
namespace exercise
{template<class T, class Con = deque<T>>//template<class T, class Con = list<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:Con _c;};
}

📁 priority_queue 介绍和使用

 📂 介绍

        优先队列也是一种容器适配器,根据严格的若排序标准,它的第一个元素总是它所包含元中最大的。

        本质上优先队列就是堆,在堆中可以随时插入元素,并且只能检索最大/小元素(优先队列中位于顶部的元素)。

        容器适配器将特定容器类封装为底层容器类,priority_queue提供一组特定的成员函数来访问其元素。元素从特定容器的尾部弹出,其称为优先队列的顶部。

        底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类,容器应该是可以通过随机访问迭代器访问,支持以下操作:

        ● empty : 检测容器是否为空。

        ● size : 返回容器中有效元素的个数。

        ● front : 返回容器第一个元素的引用。

        ● push_back:在容器尾部插入元素。

        ● pop_back:删除容器尾部元素。

        标准容器类vector和deque满足这些需求。默认情况下,使用vector作为底层容器类。

        需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数来自动完成操作。

 📂 使用

#include <iostream>
#include <queue>using namespace std;int main()
{//默认建大堆//等价于 priority_queue<int,vector<int>,less<int>>priority_queue<int> p1;    //传递仿函数 , 建小堆priority_queue<int,vector<int>,greater<int>> p2;p1.push(1);p1.push(2);p1.push(3);p2.push(3);p2.push(2);p2.push(1);//p1 : 3,2,1//p2 : 1,2,3
}

 📂 仿函数

        仿函数(Functor)是一种行为类似于函数的对象。在C++中,仿函数可以被当作函数使用,可以执行函数调用操作,并且可以具有自己的状态。

        通常情况下,仿函数是一个类,它重载了函数调用运算符operator()。通过重载该运算符,仿函数可以像函数一样被调用,接受参数并返回结果。重载了operator[]的类,就是仿函数。

        仿函数的对象可以像函数一样调用。

        仿函数可以控制比较逻辑,控制如何比较。

 📂 模拟实现

namespace exercise
{template <class T>struct less{bool operator()(const T& x, const T& y){return x < y;}};template<class T>struct greater{bool operator()(const T& x, const T& y){return  x > y;}};template<class T,class Container = vector<T>,class Compare = less<T>>class priority_queue{public:void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){//if (_con[child] > _con[parent])if(com(_con[parent],_con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}void AdjustDown(int parent){Compare com;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}if (com(_con[parent], _con[child])){std::swap(_con[child],_con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}size_t size(){return _con.size();}bool empty(){return _con.empty();}const T& top(){return _con[0];}private:Container _con;};}

📁 容器适配器

 📂 概念

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

 📂 STL库中stack和queue的底层结构

        虽然stack和queue中也可以存放元素,但在STL中并没有讲其划分为容器行列,而是将其称为容器适配器,这是因为stack和queue只是堆其他容器的接口进行包装,STL中stack和queue默认使用deque。

 📂 deque介绍

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

        deque并不是真正连续的空间,而是由一端连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,底层结构如下:

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

        deque的缺陷:

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

        和list比较,其底层空间时连续的,空间利用率特别高,不需要存储额外字段。

        但是deque有一个致命缺陷,不适合遍历,因为在遍历时,deque的迭代器要频繁的区间所是否移动到某段小空间的边界,导致效率低下,在序列式场合中,肯呢个需要经常遍历,因此在实际中,需要线性结构时,大多数有限考虑vector和list,deque的应用不多,目前的一个应用就是.STL用其为stack和queue的底层容器类。

为什么选择人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的优点,而完美的避开了其缺陷。

📁 总结

        以上,就是本期【C++杂货铺】stack和queue的主要内容了,包含了它stack,queue,priority_queue的介绍和使用方法,以及他们模拟实现他们的底层。

        此外,还介绍了仿函数是什么,就是一个冲在了operator()的类,使用它的对象就像使用函数一样。

        如果感觉本期内容对你有帮助,欢迎点赞,收藏,关注。Thanks♪(・ω・)ノ

这篇关于【C++杂货铺】详解 stack 和 queue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/890232

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

java中反射Reflection的4个作用详解

《java中反射Reflection的4个作用详解》反射Reflection是Java等编程语言中的一个重要特性,它允许程序在运行时进行自我检查和对内部成员(如字段、方法、类等)的操作,本文将详细介绍... 目录作用1、在运行时判断任意一个对象所属的类作用2、在运行时构造任意一个类的对象作用3、在运行时判断

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

MyBatis-Plus 中 nested() 与 and() 方法详解(最佳实践场景)

《MyBatis-Plus中nested()与and()方法详解(最佳实践场景)》在MyBatis-Plus的条件构造器中,nested()和and()都是用于构建复杂查询条件的关键方法,但... 目录MyBATis-Plus 中nested()与and()方法详解一、核心区别对比二、方法详解1.and()

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos