C++中的deque、stack、queue及priority_queue

文章目录

  • C++中的deque、stack、queue及priority_queue
    • 一、deque
    • 二、stack
    • 三、queue
    • 四、priority_queue
    • 五、相关注意事项

一、deque

  • 1 . deque的介绍
  1. deque(发音类似“deck”),是双端队列不规则的首字母缩写,双端队列是动态大小的序列式容器,其可以像两端进行伸缩。
  2. 特定的库可以以不同的方式实现deque,但通常都是一种动态数组。
  3. 不论在何种情况下,它都允许通过随机访问迭代器直接访问单个元素,可以根据需要动态的伸缩。
  4. 因此,deque提供了一些与vector相似的功能,但deque在头部和尾部进行数据插入和删除操作更加高效。
  5. 与vector不同的是,deque不能保证所有的元素存储在连续的空间中,在deque中通过指针加偏移量方式访问元素可能会导致非法的操作。
  6. vector与list提供了相似的接口,因此其具有类似的用途,但是内部的实现原理不同:vector使用使用了动态数组,该数组通常需要动态增长;deque中的元素可能分散在不同的存储块中
  7. 在deque中保存了一些必要的信息,通常用来在常数范围内直接访问deque中的任何一个元素,所以deque的内部实现比vector复杂,但是这些额外信息使得dque在某些情况下增长更加的高效,特别是在序列比较大,重新分配成本比较高的情况下。
  8. 除了在频繁在头部或尾部进行插入和删除操作外,deque比list和forward_list的性能更差
  • 2 deque底层的原理图

  • 3 .deque的应用场景
  • deque在序列式容器中比较鸡肋,因为如果只是简单的存储元素,使用vector即可
  • 如果对元素任意位置进行插入或者删除操作比较多,使用list即可
  • 所以一般很少去使用deque。deque最大的应用,就是用其作为标准库中stack和queue的底层结构

二、stack

  • 1.stack的介绍
  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作
  1. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。
  • 2.stack的模拟实现
#include<deque>namespace wolf
{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

  • 1.queue的介绍
  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列
  1. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque
  • 2.queue的模拟实现
#include<deque>namespace wolf
{template<class T, class Con = deque<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

  • 1.priority_queue的介绍
  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素
  • 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
  • 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作
  • 2.priority_queue的使用
  • 优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆
  • 所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆

处理内置类型的情况:

#include <vector>
#include <queue>
#include <functional> // greater算法的头文件void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}
  • 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载
class Date
{public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载priority_queue<Date> q1;q1.push(Date(2018, 10, 29));q1.push(Date(2018, 10, 28));q1.push(Date(2018, 10, 30));cout << q1.top() << endl;// 如果要创建小堆,需要用户提供>的重载priority_queue<Date, vector<Date>, greater<Date>> q2;q2.push(Date(2018, 10, 29));q2.push(Date(2018, 10, 28));q2.push(Date(2018, 10, 30));cout << q2.top() << endl;
}
  • 有些情况下,用户可能需要提供比较器规则
class Less
{public:bool operator()(const Date* pLeft, const Date* pRight){return *pLeft < *pRight;}
};void TestPriorityQueue()
{// 自己定制比较的规则priority_queue<Date*, vector<Date*>, Less> q;q.push(&Date(2018, 10, 29));q.push(&Date(2018, 10, 28));q.push(&Date(2018, 10, 30));cout << *q.top() << endl;return 0;
}
  • priority_queue的模拟实现
namespace wolf
{template <class T, class Sequence = vector<T>, class Compare = less<T> >class priority_queue{public:priority_queue() : c(){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last): c(first, last){make_heap(c.begin(), c.end(), comp);}bool empty() const { return c.empty(); }size_t size() const { return c.size(); }T& top() const { return c.front(); }void push(const T& x){c.push_back(x);push_heap(c.begin(), c.end(), comp);}void pop(){pop_heap(c.begin(), c.end(), comp);c.pop_back();}private:                                                                                                                      Sequence c;Compare comp;};}

五、相关注意事项

  • 1.为什么使用deque作为stack和queue的底层结构?

  • 首先deque的优点是头部和尾部操作方便,效率可以达到O(1),缺点是因为deque的底层空间是不连续的,之所以看起来是连续的都是迭代器的功劳

  • 正是因为deque的空间不连续,所以对其遍历的效率极低,因为要判断寻找下一段空间的位置。

  • 而stack和queue是作为容器适配器来使用的,其不需要遍历,只需要在两端进行操作即可,刚好避开deque的缺陷。

  • 虽然其他容器也可以作为stack和queue的底层结构,但效率都没有deque高

  • 2.什么是容器适配器?

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

  • 3.为什么将stack、queue和priority_queue称作为容器适配器?

  • 虽然stack、queue、priority_queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为每个容器在底层都有自己的实现方式,而stack、queue、priority_queue只是在底层将其他容器进行了封装

C++中的deque、stack、queue及priority_queue相关推荐

  1. stl的set,multiset, map, multimap, deque, list, stack, queue, priority_queue

    set实际上是平衡二叉树,需要声明头文件#include<set> Insert:将元素插入集合中 使用前向迭代器对集合中序遍历 使用反向迭代器reverse_iterator可以反向遍历 ...

  2. [C++](13)stack queue priority_queue 模拟实现:容器适配器,deque介绍,仿函数详解

    文章目录 使用 stack 栈 queue 队列 priority_queue 优先级队列 什么是容器适配器? deque 容器简单介绍 模拟实现 stack queue priority_queue ...

  3. deque stack java_一文弄懂java中的Queue家族

    简介 java中Collection集合有三大家族List,Set和Queue.当然Map也算是一种集合类,但Map并不继承Collection接口. List,Set在我们的工作中会经常使用,通常用 ...

  4. C++知识点25——使用C++标准库(容器适配器stack、queue、priority_queue)

    除了vector,list,deque等常用的容器,还有根据这些常用的容器进行改造来满足特殊要求的容器,这些特殊容器的行为和常用容器很相近,也称为容器适配器. 常用的容器适配器有三个,分别是stack ...

  5. C++---容器适配器(stack、queue、priority_queue)

    容器适配器 首先我们要知道容器适配器是干啥的. 我们可以简单的将容器适配器当做一个接口装置.有的电脑上没有数据转接口,但是有usb接口,这是我们没必要重新买一个电脑,我们可以做一个usb数据转接线.而 ...

  6. c++--stack,queue,priority_queue

    前言 对于栈和队列我们是不陌生的,在数据结构阶段已经学习过,记得当时我们还是用c语言将它一步一步造出来,因为压栈与出栈正好满足数组的尾插与头删,数组的代价是及小的.对于队列是头出队列,尾插.所以就栈的 ...

  7. 模拟stack/queue/priority_queue

    stack要点 1.stack遵从先进后出的规则,即先进栈的元素后出栈,入栈/出栈只能在栈的一端进行 2.stack是作为容器适配器被实现的,容器适配器是对特定类进行封装,作为其底层的容器 3.sta ...

  8. 源码阅读(34):Java中线程安全的Queue、Deque结构——ArrayBlockingQueue(4)

    (接上文<源码阅读(33):Java中线程安全的Queue.Deque结构--ArrayBlockingQueue(3)>) 2.3.3.3.forEachRemaining() 方法 f ...

  9. 源码阅读(32):Java中线程安全的Queue、Deque结构——ArrayBlockingQueue(2)

    (接上文<源码阅读(31):Java中线程安全的Queue.Deque结构--ArrayBlockingQueue(1)>) 本篇内容我们专门分析ArrayBlockingQueue中迭代 ...

最新文章

  1. 手撕 CNN 经典网络之 VGGNet(理论篇)
  2. 基于query语句解析mysql工作原理
  3. Basic Calculator 基本计算器-Leetcode
  4. 002 html总结
  5. docker network bridge模式,自定义(一)
  6. Atlassian JIRA 插件开发之三 创建
  7. Spring源码之动态AOP自定义标签
  8. 我的vs2010扩展备忘.jpg
  9. 解决android Studio 安装完运行提示failed to find build tools revision 24.0.2
  10. 博后招募 | 香港中文大学招收机器人视觉智能传感方向博士后/RA/访问学者
  11. win10服务器怎么连接显示器不亮,Win10检测不到第二个显示器怎么解决?Win10外接显示器黑屏解决方法...
  12. java获取字符串的最后一个字符_如何获取字符串的最后一个字符
  13. 阶段巨献 - centos+php-fpm+mariaDB+svn+nodejs+redis(开机启动及配置远程连接),配置linux的php和nodejs网站运行环境。
  14. 数据链路层 - MTU 、ARP协议
  15. [教程] 关于一种比较特别的线段树写法
  16. 不同Normalization之间的比较
  17. C语言求6阶余子式,usdt交易 -usdt交易V3.6.39
  18. ASP.NET 2.0 本地化技术之研究
  19. 借助Microsoft Teams进行在线学习小组的组织与管理
  20. 【我参加NVIDIA Sky Hackathon】CV篇

热门文章

  1. 大数据(1) - 虚拟机集群搭建
  2. OKWatchDog 打造一个安全的容器类
  3. tengine安装问题
  4. CodeForces - 1512G Short Task(欧拉筛求因子和)
  5. CodeForces - 787D - Legacy(线段树优化建图+最短路)
  6. HihoCoder - 1873 Frog and Portal(构造+进制拆分)
  7. CodeForces - 1316B String Modification(找规律)
  8. HDU - 4784 Dinner Coming Soon(bfs+动态规划+优先队列)
  9. HDU - 3538 A sample Hamilton path(最短哈密顿路径+状压dp)
  10. Jupyter Notebook导入自定义模块