【C++ 学习 ⑭】- 详解 stack、queue 和 priority_queue 容器适配器

目录

一、详解 C++ STL 容器适配器

1.1 - 什么是容器适配器?

1.2 - 容器适配器的种类

二、详解 C++ STL deque 容器

2.1 - deque 的原理介绍

2.2 - deque 的优缺点

三、详解 stack 容器适配器

3.1 - stack 的基本介绍

3.2 - stack 的成员函数

3.3 - stack 的模拟实现

四、详解 queue 容器适配器

4.1 - queue 的基本介绍

4.2 - queue 的成员函数

4.3 - queue 的模拟实现

五、详解 priority_queue 容器适配器

5.1 - priority_queue 的基本介绍

5.2 - priority_queue 的成员函数

5.3 - priority_queue 的模拟实现


 

 


一、详解 C++ STL 容器适配器

1.1 - 什么是容器适配器?

在详解什么是容器适配器之前,初学者首先要理解适配器的含义。

其实,容器适配器中的 "适配器",和生活中常见的电源适配器中的 "适配器" 的含义非常接近。我们知道,无论是电脑、手机还是其它电器,充电时都无法直接使用 220V 的交流电,为了方便用户使用,各个电器厂商都会提供一个适用于自己产品的电源适配器,它可以将 220V 的交流电转换成适合电器使用的低压直流电。

具有多种功能的电源适配器,可以满足多种需求:

7440d4c74e8341098eca2cab820ef393.png

 

因此简单理解,容器适配器就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。容器适配器的底层即通过封装某个序列式容器,并重新组合该容器中包含的成员函数,使其满足特定场景的需要

容器适配器本质上还是容器,只不过此容器类模板的实现,利用了大量其他基础容器类模板中已经写好的成员函数。当然,如果必要的话,容器适配器中也可以自创新的成员函数

需要注意的是,STL 中的容器适配器,其内部使用的基础容器并不是固定的,用户可以在满足特定条件的多个基础容器中自由选择

 

1.2 - 容器适配器的种类

STL 提供了 3 种容器适配器,分别为 stack 栈适配器、queue 队列适配器以及 priority_queue 优先权队列适配器

容器适配器基础容器需要包含的成员函数满足条件的基础容器默认使用的基础容器
stackempty()、size()、back()、push_back()、pop_back()vector、deque、listdeque
queueempty()、size()、front()、back()、push_back()、pop_front()deque、listdeque
priority_queueempty()、size()、front()、push_back()、pop_back()vector、dequevector

因为删除 vector 容器的头部元素需要移动大量元素,效率较低,所以 vector 容器没有提供 pop_front 成员函数,因此其不能作为 queue 的基础容器

因为 list 容器不支持随机访问,所以其不能作为 priority_queue 的基础容器

由于不同的序列式容器其底层采用的数据结构不同,因此容器适配器的执行效率也不尽相同,但通常情况下,使用默认的基础容器即可。

 

 


二、详解 C++ STL deque 容器

2.1 - deque 的原理介绍

deque 是 double-ended queue 的缩写,又称双端队列容器

deque 容器和 vector 容器有很多相似的地方,例如:deque 容器也擅长在序列尾部插入或删除元素(时间复杂度为 O(1) 常数阶),而不擅长在序列中间添加或删除元素。和 vector 不同的是,deque 还擅长在序列头部插入或删除元素,时间复杂度也为 O(1) 常数阶,并且更重要的一点是,deque 并不是连续的空间,而是由一段段小空间拼接而成的,实际 deque 类似于一个动态二维数组,其底层结构如下图所示

3b64b0bcf9c24d7b8047dc13b5e859dd.png

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

da192373c061412db5f8b549da0c217c.png

 

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

d33463aca65f4b6ba1c1bd1188b94652.png

 

 

2.2 - deque 的优缺点

和 vector 相比,deque 的优点:在头部插入和删除元素时,不需要移动元素,效率较高,而且在扩容时,也不需要移动大量的元素。

和 list 相比,deque 的优点:空间利用率较高,不需要存储额外字段。

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

  1. stack 和 queue 不需要遍历(因此 stack 和 queue 没有迭代器),只需要在固定的一端或两端进行操作;

  2. 在 stack 元素增长时,deque 比 vector 的效率高(扩容时不需要移动大量元素);queue 中的元素增长时,deque 不仅效率高,而且空间利用率高。

即利用了 deque 的优点,而完美地避开了其缺点。

 

 


三、详解 stack 容器适配器

3.1 - stack 的基本介绍

stack 以类模板的形式定义在 <stack> 头文件中,并位于 std 命名空间中。

template <class T, class Container = deque<T> > class stack;

stack 是一种容器适配器,专门设计用于在后进先出(LIFO,last-in first-out)的环境中使用,元素只能从容器的一端进行插入和删除。

 

526efcd1e4ae4708a6047aefe182f903.png

 

3.2 - stack 的成员函数

构造函数:

explicit stack(const container_type& ctnr = container_type());

注意:container_type 等价于 Container

构造一个 stack 容器适配器对象

empty:

bool empty() const;

size:

size_type size() const;

top:

      value_type& top();
const value_type& top() const;

push:

void push(const value_type& val);

pop:

void pop();

示例

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

 

3.3 - stack 的模拟实现

#pragma once
​
#include <deque>
​
namespace yzz
{template<class T, class Container = std::deque<T>>class stack{public:bool empty() const{return _ctnr.empty();}
​size_t size() const{return _ctnr.size();}
​T& top(){return _ctnr.back();}
​const T& top() const{return _ctnr.back();}
​void push(const T& val){_ctnr.push_back(val);}
​void pop(){_ctnr.pop_back();}private:Container _ctnr;};
}

 

 


四、详解 queue 容器适配器

4.1 - queue 的基本介绍

queue 以类模板的形式定义在 <queue> 头文件中,并位于 std 命名空间中。

template < class T, class Container = deque<T> > class queue;

queue 是一种容器适配器,专门设计用于在先进先出(FIFO,first-in first-out)的环境中使用,元素只能从容器的一端插入,并从另一端删除。

1a98d7c9fbfe4fb8b8aff847b8871a41.png

 

 

4.2 - queue 的成员函数

构造函数:

explicit queue(const container_type& ctnr = container_type());

empty:

bool empty() const;

size:

size_type size() const;

front:

      value_type& front();
const value_type& front() const;

back:

      value_type& back();
const value_type& back() const;

push:

void push(const value_type& val);

pop:

void pop();

示例

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

 

4.3 - queue 的模拟实现

#pragma once
​
#include <deque>
​
namespace yzz
{template<class T, class Container = std::deque<T>>class queue{public:bool empty() const{return _ctnr.empty();}
​size_t size() const{return _ctnr.size();}
​T& front(){return _ctnr.front();}
​const T& front() const{return _ctnr.front();}
​T& back(){return _ctnr.back();}
​const T& back() const{return _ctnr.back();}
​void push(const T& val){_ctnr.push_back(val);}
​void pop(){_ctnr.pop_front();}private:Container _ctnr;};
}

 

 


五、详解 priority_queue 容器适配器

5.1 - priority_queue 的基本介绍

priority_queue 以类模板的形式定义在<queue> 头文件中,并位于 std 命名空间中。

template < class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue; 

priority_queue 是一种容器适配器,其模拟的也是队列这种存储结构,即使用此容器适配器存储元素,只能从一进(称为队尾),从另一端出(称为队头),且每次只能访问 priority_queue 中位于队头的元素。

但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 "first-in first-out"(先进先出)原则,而是 "first-in largest-out" 原则,即先进队列的元素不一定先出队列,而是优先级最大的元素先出队列

priority_queuue 容器适配器的 "first-in largest-out" 特性,和它底层采用堆(heap)结构存储数据是分不开的,注意:priority_queue 默认情况下是大根堆

 

5.2 - priority_queue 的成员函数

构造函数:

initialize (1) explicit priority_queue(const Compare& Cmp = Compare(), const Container& ctnr = Container());range (2) template <class InputIterator>priority_queue(InputIterator first, InputIterator last,const Compare& Cmp = Compare(), const Container& ctnr = Container()));

empty:

bool empty() const;

size:

size_type size() const;

top:

const value_type& top() const;

push:

void push(const value_type& val);

pop:

void pop();

示例一

#include <iostream>
#include <queue>
using namespace std;
​
int main()
{priority_queue<int> pq;pq.push(30);pq.push(100);pq.push(25);pq.push(40);cout << pq.size() << endl;  // 4while (!pq.empty()){cout << pq.top() << " ";pq.pop();}// 100 40 30 25cout << endl;return 0;
}

示例二 - 如果 priority_queue 中存储的是自定义类型的数据,用户则需要在自定义类型中提供 < 和 > 的重载

#include <iostream>
#include <queue>
using namespace std;
​
class Date
{friend ostream& operator<<(ostream& out, const Date& d);
public:Date(int year = 1949, int month = 10, 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);}
private:int _year;int _month;int _day;
};
​
ostream& operator<<(ostream& out, const Date& d)
{return out << d._year << "-" << d._month << "-" << d._day;
}
​
int main()
{priority_queue<Date, vector<Date>, greater<Date>> pq;pq.push(Date(2023, 5, 1));pq.push(Date(2023, 7, 1));pq.push(Date(2023, 6, 1));pq.push(Date(2023, 4, 1));cout << pq.size() << endl;  // 4while (!pq.empty()){cout << pq.top() << " ";pq.pop();}// 2023-4-1 2023-5-1 2023-6-1 2023-7-1cout << endl;return 0;
}

 

5.3 - priority_queue 的模拟实现

#pragma once
​
#include <vector>
#include <assert.h>
​
namespace yzz
{// 函数对象(仿函数)类template<class T>struct less{bool operator()(const T& left, const T& right){return left < right;}};
​template<class T>struct greater{bool operator()(const T& left, const T& right){return left > right;}};
​
​// priority_queue 容器适配器template<class T, class Container = std::vector<T>, class Compare = less<T>>class priority_queue{private:void AdjustUp(int child){Compare cmp;int parent = (child - 1) / 2;while (child > 0){if (cmp(_ctnr[parent] ,_ctnr[child])){std::swap(_ctnr[parent], _ctnr[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}
​void AdjustDown(int parent){Compare cmp;int sz = _ctnr.size();int child = 2 * parent + 1;  // 双亲节点默认和其左孩子进行比较while (child < sz){if (child + 1 < sz && cmp(_ctnr[child] ,_ctnr[child + 1])){++child;  // 改为让双亲节点和其右孩子进行比较}
​if (cmp(_ctnr[parent] ,_ctnr[child])){std::swap(_ctnr[parent], _ctnr[child]);parent = child;child = 2 * parent + 1;}else{break;}}}
​public:priority_queue() { }
​template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){push(*first);++first;}}
​bool empty() const{return _ctnr.empty();}
​size_t size() const{return _ctnr.size();}
​const T& top() const{return _ctnr.front();}
​void push(const T& val){_ctnr.push_back(val);AdjustUp(_ctnr.size() - 1);}
​void pop(){assert(!_ctnr.empty()); // 前提是 _ctnr 非空std::swap(_ctnr[0], _ctnr[_ctnr.size() - 1]);_ctnr.pop_back();AdjustDown(0);}private:Container _ctnr;};
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49514.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

androidstudio Please specify a signing configuration for this variant (release)

当直接运行release版本时&#xff0c;报错Error: The apk for your currently selected variant cannot be signed. Please specify a signing configuration for this variant (package64-release). 解决报错&#xff1a;添加签名&#xff0c;signingConfigs 写在buildTypes前…

java八股文面试[java基础]——final 关键字作用

为什么局部内部类和匿名内部类只能访问final变量&#xff1a; 知识来源 【基础】final_哔哩哔哩_bilibili

壁仞科技与百度飞桨完成II级兼容性测试

近日&#xff0c;壁仞科技BR104通用GPU与百度飞桨已完成II级兼容性测试。测试结果显示&#xff0c;双方兼容性表现良好&#xff0c;整体运行稳定。这是壁仞科技加入飞桨“硬件生态共创计划”后的阶段性成果。产品兼容性证明本次II级兼容性测试完成了涵盖自然语言处理、计算机视…

服务器的介绍

1.服务器概述 1.1 服务器的基本概念 服务器是计算机的一种&#xff0c;是网络中为客户端计算机提供各种服务的高性能计算机&#xff1b; 服务器在网络操作系统的控制下&#xff0c;将与其相连的硬盘、磁带、 打印机及昂贵的专用通讯设备提供给网络上的客户站点共享&#xf…

【Unity3D赛车游戏】【二】如何制作一个真实模拟的汽车

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

C# 学习笔记

C# 学习笔记 Chapter 1 C# 基础部分Section 1 类与命名空间Part 1 命名空间 NameSpacePart 2 类 Class Section 2 基本元素Section 3 数据类型Part 1 什么是类型&#xff1f;Part 2 类型在 C Sharp 中的作用Part 3 C Sharp 中的数据类型 Section 4 变量、对象与内存Part 1 变量…

k8s扩缩容与滚动更新

使用kubectl run创建应用 kubectl run kubernetes-bootcamp \> --imagedocker.io/jocatalin/kubernetes-bootcamp:v1 \> --port8080 端口暴露出去 kubectl expose pod kubernetes-bootcamp --type"NodePort" --port 8080 使用kubectl create创建应用 kubect…

stack和queue的模拟实现

stack和queue的模拟实现 容器适配器什么是适配器STL标准库中stack和queue的底层结构deque的简单介绍deque的缺陷 stack模拟实现queue模拟实现priority_queuepriority_queue的使用priority_queue的模拟实现 容器适配器 什么是适配器 适配器是一种设计模式(设计模式是一套被反复…

【C++】红黑树

目录 一、红黑树的概念二、红黑树的性质三、红黑树的插入操作四、红黑树的验证五、红黑树和AVL树的比较六、代码 一、红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从…

设计模式(9)建造者模式

一、 1、概念&#xff1a;将一个复杂对象的构造与它的表示分离&#xff0c;使得同样的构造过程可以创建不同的表示。建造者模式主要用于创建一些复杂的对象&#xff0c;这些对象内部构建间的顺序通常是稳定的&#xff0c;但对象内部的构建通常面临着复杂的变化&#xff1b;建造…

[SpringBoot3]Web服务

五、Web服务 基于浏览器的B/S结构应用十分流行。SpringBoot非常适合Web应用开发&#xff0c;可以使用嵌入式Tomcat、Jetty、Undertow或Netty创建一个自包含的HTTP服务器。一个SpringBoot的Web应用能够自己独立运行&#xff0c;不依赖需要安装的Tomcat、Jetty等。SpringBoot可以…

indexDB入门到精通

前言 由于开发3D可视化项目经常用到模型&#xff0c;而一个模型通常是几m甚至是几十m的大小对于一般的服务器来讲加载速度真的十分的慢&#xff0c;为了解决这个加载速度的问题&#xff0c;我想到了几个本地存储的。 首先是cookie,cookie肯定是不行的&#xff0c;因为最多以只…

Vue的Ajax请求-axios、前后端分离练习

Vue的Ajax请求 axios简介 ​ Axios&#xff0c;是Web数据交互方式&#xff0c;是一个基于promise [5]的网络请求库&#xff0c;作用于node.js和浏览器中&#xff0c;它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生node.js http模块, 而在…

SpringBoot +Vue3 简单的前后端交互

前端&#xff1a;Vue3 创建项目&#xff1a; npm create vuelatest > cd <your-project-name> > npm install > npm run dev 项目结构图如下&#xff1a; 1、查看入口文件内容&#xff1a;main.js 代码如下&#xff1a; import ./assets/main.css impor…

自己实现 SpringMVC 底层机制 系列之-实现任务阶段 6-完成控制器方法获取参数-@RequestParam

&#x1f600;前言 自己实现 SpringMVC 底层机制 系列之-实现任务阶段 6-完成控制器方法获取参数-RequestParam &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c…

攻防世界-Web_php_include

原题 解题思路 php://被替换了&#xff0c;但是只做了一次比对&#xff0c;改大小写就可以绕过。 用burp抓包&#xff0c;看看有哪些文件 flag明显在第一个PHP文件里&#xff0c;直接看

飞天使-k8s基础组件分析-pod

文章目录 pod介绍pod 生命周期init 容器容器handlerpod中容器共享进程空间sidecar 容器共享 参考链接 pod介绍 最小的容器单元 为啥需要pod? 答: 多个进程丢一个容器里&#xff0c;会因为容器里个别进程出问题而出现蝴蝶效应&#xff0c;pod 是更高级的处理方式pod 如何共享相…

【李群李代数】李群控制器(lie-group-controllers)介绍——控制 SO(3) 空间中的系统的比例控制器Demo...

李群控制器SO(3)测试 测试代码是一个用于控制 SO(3) 空间中的系统的比例控制器。它通过计算控制策略来使当前状态逼近期望状态。该控制器使用比例增益 kp 进行参数化&#xff0c;然后进行一系列迭代以更新系统状态&#xff0c;最终检查状态误差是否小于给定的阈值。这个控制器用…

摩托车外廓尺寸检测软件

本系统为摩托车外廓尺寸检测软件&#xff0c;该系统共涉及两种测量方法&#xff1a;自动测量和手动测量&#xff0c;旨在测量出每一台摩托车的外廓尺寸&#xff0c;包括但不限于摩托车的车长、车宽、车高、轮距、前悬、后悬、前伸距等需要测量的参数&#xff0c;可通过运行软件…

二、Kafka快速入门

目录 2.1 安装部署1、【单机部署】2、【集群部署】 2.2 Kafka命令行操作1、查看topic相关命令参数2、查看当前kafka服务器中的所有Topic3、创建 first topic4、查看 first 主题的详情5、修改分区数&#xff08;注意&#xff1a;分区数只能增加&#xff0c;不能减少&#xff09;…