容器适配器中stack queue priority_queue的介绍及模拟实现

news/2024/11/9 9:40:21/

文章目录

  • 容器适配器的概念
  • deque的介绍及底层结构
  • stack的介绍
    • stack的模拟实现
  • queue的介绍
    • queue的模拟实现
  • priority_queue的介绍
    • priority_queue的模拟实现

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

deque的介绍及底层结构
要想摸清stack、queue的底层我们就要先学习deque,因为在STL中stack、queue等容器适配器的底层都是默认用deque进行的封装,从而达到我们想要的接口,下图是STL官方文档中stack、queue的接口参数图,可以看到默认的底层容器。
在这里插入图片描述

deque的底层
deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要移动元素;与list比较,空间利用率比较高。
在这里插入图片描述
deque并不是真正连续的空间,而是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,所以deque的迭代器就比较复杂,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的优缺点:与vector相比,头部插入元素、删除元素deque比vector要快,扩容方面,deque不需要挪动数据,vector则需要,与list相比,deque的底层是连续的空间,list不是,所以比list的空间利用率高,缺点是deque不适合遍历,相比于vector、list,deque的遍历需要大量的检查边界,效率不高,所以deque不适合需要大量遍历数据的场景,而stack、queue等不需要遍历,所以完美的避开了deque的缺点。

stack的介绍
在这里插入图片描述

  1. stack是一种容器适配器,专门用在具有后进先出操作的环境中,其删除只能从容器的一端进行元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. 满足stack的底层容器有vector、list、deque,默认情况下不指定容器,则使用deque。
    4.

stack的模拟实现

namespace Lh
{//template <class T>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://vector<T> _con;Container _con;};
}

queue的介绍
在这里插入图片描述

  1. 队列是一种容器适配器,专门用于在先进先出环境中操作,其中从容器一端插入元素,另一端提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 满足stack的底层容器有list、deque,默认情况下不指定容器,则使用deque。
    在这里插入图片描述

queue的模拟实现

namespace Lh
{//template <class T>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;};
}

priority_queue的介绍
在这里插入图片描述

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 满足stack的底层容器有vector、deque,默认情况下不指定容器,则使用vector。
  5. 需要支持随机访问迭代器,以便始终在内部保持堆结构,priority_queue默认是大堆。

priority_queue的模拟实现

namespace Lh
{//Compare 实例化进行比较的仿函数    less -> 大堆      //Compare 实例化进行比较的仿函数    greater -> 小堆   template <class T, class Container = vector<T>, class Compare = std::less<T>>class priority_queue     //默认是大堆 也就是降序 {public:priority_queue(){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last)  //迭代器区间构造{while (first != last){_con.push_back(*first);++first;}//向下调整建堆for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){adjust_down(i);}}void adjust_up(size_t child)   //向上调整{Compare com;               //用这个类型实例化一个对象 默认是lesssize_t parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up(_con.size()-1);}void adjust_down(size_t parent)  //向下调整{Compare com;    size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child += 1;}if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){assert(_con.size() > 0);std::swap(_con[0], _con[_con.size() - 1]);  //最后一个和堆顶的交换 然后删除最后一个_con.pop_back();adjust_down(0);}bool empty() const{return _con.empty();}const T& top() {assert(_con.size() > 0);//return _con[0];return _con.front();}size_t size() const{return _con.size();}private:Container _con;};//仿函数/函数对象   是一个类  重载了operator()template <class T>class less{public:bool operator()(const T& l, const T& r) const{return l < r;}};template<class T>class greater {public:bool operator()(const T& l, const T& r) const{return l > r;}};
}

http://www.ppmy.cn/news/11350.html

相关文章

Android基础知识整理(一)活动 Activity

会先整理四大组件&#xff1a;活动Activity、服务Service、内容提供器ContentProvider、广播接收器BroadcastReceiver的学习笔记。 随后整理UI笔记&#xff0c;然后是一些库的学习以及Android多线程的学习。持续更新文章目录活动(Activity)一、概念二、主要内容2.1 Intent2.1.1…

【C语言】指针进阶(一)

学好指针✊✊✊还有&#xff0c;男孩子在外面要保护好自己一、字符指针字符也有地址&#xff0c;当然可以将其储存——字符指针&#xff0c;是储存字符地址的指针对于普通的单个字符&#xff1a;char ch a;char* pc1 &ch;这里的pc是单个变量ch‘&#xff08;单个字符&…

Elasticsearch 核心技术(四):索引管理、映射管理、文档管理(REST API)

❤️ 个人主页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;大数据核心技术从入门到精通 文章目录一、索引管理1. 创建索引创建一个索引索引设置映射字段别名2. 获取索引3. 删除索…

云天励飞在科创板获准注册:计划募资30亿元,陈宁为实际控制人

2023年1月10日&#xff0c;证监会发布公告&#xff0c;同意深圳云天励飞技术股份有限公司&#xff08;下称“云天励飞”&#xff09;首次公开发行股票注册。据贝多财经了解&#xff0c;云天励飞于2020年12月8日在科创板递交上市申请&#xff0c;2021年8月6日过会。 本次冲刺上市…

【vue2】组件进阶与插槽详解

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;v-modedl表单双向绑定、ref|$ref操作dom、dynamic动态组件、$nextTick同步、匿名插槽、具…

结构体内存对齐与结构体位段:学习笔记8

目录 一.结构体基础知识 1. 结构体的特殊声明 2. 结构的自引用 3.结构体变量的定义和初始化 二.结构体内存对齐 1.关键概念&#xff1a; 2.计算示例 3.嵌套结构体的内存计算 4.结构体内存对齐的意义 5.定义结构体时的注意事项 6.修改默认对齐数 附&#xff1a;关…

Linux进程状态与系统负载检测

1.基础知识-进程的5个状态进程可以分为五个状态&#xff0c;分别是&#xff1a;1&#xff09;创建状态一个应用程序从系统上启动&#xff0c;首先就是进入创建状态&#xff0c;需要获取系统资源创建进程管理块&#xff08;PCB&#xff09;完成资源分配。2) 就绪状态在创建状态完…

Java多线程案例——定时器

一&#xff0c;定时器1.定时器的概念定时器是Java开发中一个重要的组件&#xff08;功能类似于闹钟&#xff09;&#xff0c;可以指定一个任务在多长时间后执行&#xff08;尤其在网络编程的时候&#xff0c;如果网络卡顿很长时间没有响应用户的需求&#xff0c;此时可以使用定…