【C++】Stack Queue 仿函数

📝前言:
这篇文章我们来讲讲STL中的stack和queue。因为前面我们已经有了string、vector和list的学习基础,所以这篇文章主要关注一些stackqueue的细节问题,以及了解一下deque(缝合怪)和priority_queue ,并且模拟实现priority_queue

🎬个人简介:努力学习ing
📋个人专栏:C++学习笔记
🎀CSDN主页 愚润求学
🌄其他专栏:C语言入门基础,python入门基础,python刷题专栏


文章目录

  • 一,Stack && queue
    • 1. 用vector 适配 Stack
    • 2. 用list模拟实现queue
    • 3. 简单认识deque
  • 二,priority_queue
    • 1. 认识优先级队列
    • 2. 仿函数
    • 3. 模拟实现priority_queue

一,Stack && queue

  1. stackqueue其实是container adaptor(容器适配器)
    在这里插入图片描述
    在STL里面他们是用deque来适配的。也就是通过deque来封装,内部实际上用的是deque的接口。

  2. stack.top()返回的是栈顶元素的引用,queue.front()一样

  3. stack.pop()并不会返回值,而是直接pop掉栈顶元素,queue.pop()一样

除了deque能做适配器以外,其他的容器也都可以,比如vector和list

1. 用vector 适配 Stack

对于Stack而言,要实现的是同一边删除与插入的操作,而vector里面正好有pop_back和push_back 这样的接口。

#include<vector>namespace tr
{template<typename T>class stack{public:stack(){}void push(const T& x) { _a.push_back(x); }void pop() { _a.pop_back(); }const T& top() const { return _a.back(); }T& top() { return _a.back(); }size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:std::vector<T> _a; // 栈的底层用数组};
}

测试代码:

#include<iostream>
#include<vector>
#include"Stack.h" using namespace std;void test_Stack() {tr::stack<int> st;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);while (!st.empty()){cout << st.top() << endl;st.pop();}cout << st.empty() << st.size() << endl;
}int main() {test_Stack();return 0;
}

注意头文件和using namespace std;的位置问题:头文件展开时会向上找标识符,比如“Stack.h”用了一个cout,但是using namespace std;在下面,向上找不到就会报错编译错误:“未定义标识符”


2. 用list模拟实现queue

list要满足的要求是一边插入一边删除,由于vector没有头删,所以这时候选择list是更好的

模拟实现:

#pragma once
#include<list>namespace tr
{template<typename T>class queue{public:queue() {}void push(const T& x) { _a.push_back(x); }const T& front() const { return _a.front(); }T& front() { return _a.front(); }void pop() { _a.pop_front(); } // 头删size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:std::list<T> _a;};}

测试代码:

#include<iostream>
#include"Queue.h" using namespace std;void test_Queue() {tr::queue<int> ls;ls.push(1);ls.push(2);ls.push(3);ls.push(4);ls.push(5);while (!ls.empty()){cout << ls.front() << endl;ls.pop();}cout << "empty: " << ls.empty() << endl << "size: " << ls.size() << endl;
}int main() {test_Queue();return 0;
}

运行结果:
在这里插入图片描述


3. 简单认识deque

deque是双端队列,即两边都可以插入和删除

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个
动态的二维数组,其底层结构如下图所示:
在这里插入图片描述
map中控是一个指针数组,每个指针指向一个数组(每个数组大小一样),这些数组才是存储数据真正的地方。
迭代器由四个部分组成:

  • 给定一个“下标” x 找到容器中对应的数据:先 x / n:找到对应的数组编号,再 x % n 找到在组内的位置
  • 判断是否到达一个数组的尾部:cur == last

deque 和 vector 以及 list 的比较:

  1. 头插尾插效率更高
  2. 下标随机访问比vector差一点
  3. 中间插入数据效率低,因为要移动数据

由因为:

  1. stack和queue没有迭代器,不需要访问
  2. 实现stack时:deque的扩容效率比vector高
  3. 实现queue时:一次性申请一块数组,在queue元素个数增长时,不需要想list一样一个个申请,效率更高,且内存利用率更高

所以,stack和queue用了deque做适配器。


二,priority_queue

1. 认识优先级队列

priority_queue:优先队列,也在头文件< queue > 里面
意思是:在使用top()pop()的时候会取优先级高的,默认是大的元素优先级高。(简单来说就是降序)
底层实现时堆,而堆的底层是数组。
在这里插入图片描述

简单使用一下:

int main() {priority_queue<int> pq;pq.push(3);pq.push(2);pq.push(6);pq.push(1);pq.push(8);while (!pq.empty()){cout << pq.top();pq.pop();}return 0;
}

运行结果:
在这里插入图片描述


2. 仿函数

仿函数是一个类,但是可以像调用函数一样去调用这个类,作为回调函数使用。通过重载()来实现

仿函数使用示例:

class Adder {
public:// 重载 () 运算符int operator()(int a, int b) const {return a + b;}
};int main() {Adder adder;// 像调用函数一样调用仿函数对象int result = adder(3, 4); // 或者用匿名对象:Adder()(3, 4) Adder()——创建匿名对象,(3 ,4)调用重载的()std::cout << "Result: " << result << std::endl;return 0;
}

3. 模拟实现priority_queue

priority_queue头文件:

#pragma once
#include<iostream>
#include<vector>
using namespace std;template<class T>
class Less
{
public:bool operator()(const T& a, const T& b){return a < b;}
};template<class T>
class Greater
{
public:bool operator()(const T& a, const T& b){return a > b;}
};namespace tr
{template<class T, class Container = vector<T>, class Compare = Less<T>>// Compare 就是比较方法class priority_queue{public:void Adjustup(size_t child){Compare com; // 构造仿函数对象size_t parent = (child - 1) / 2;while (child > 0){if (com(_a[child], _a[parent])) // 用仿函数对象调用仿函数{std::swap(_a[child], _a[parent]);child = parent;parent = (child - 1) / 2;}else {break;}}}void Adjustdown(size_t parent){Compare com;size_t child = parent * 2 + 1;while (child < _a.size()){if (child + 1 < _a.size() && com(_a[child + 1], _a[child])){child++;}if (com(_a[child], _a[parent])) // 相当于孩子节点小于父亲{std::swap(_a[child], _a[parent]);parent = child;child = parent * 2 + 1;}else {break;}}}priority_queue(){}void push(const T& x){_a.push_back(x);Adjustup(_a.size() - 1);}T& top(){return _a[0];}const T& top() const{return _a[0];}void pop(){std::swap(_a[0], _a[_a.size() - 1]);_a.pop_back();Adjustdown(0);}size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:Container _a;};};

测试代码:

#include"priority_queue.h"
int main() {tr::priority_queue<int, vector<int>, Greater<int>> pq; // 传入的不是less,而是Less<int>,类模板传的是类型,函数模板传才是参数pq.push(3);pq.push(2);pq.push(6);pq.push(1);pq.push(8);while (!pq.empty()){cout << pq.top();pq.pop();}cout << endl;return 0;
}

运行结果(大根堆,降序):
在这里插入图片描述

补充小知识点:编译器对模板是按需实例化,首先编译时:只会检查模板的大框架,不会检查类里面函数的内部。第二,当没有使用到类中的成员函数时,编译器在实例化的时候就不会实例化这些函数。(所以有的时候可能类的成员函数有问题,只是没使用到)


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

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

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

相关文章

[实战] 天线阵列波束成形原理详解与仿真实战(完整代码)

天线阵列波束成形原理详解与仿真实战 1. 引言 在无线通信、雷达和声学系统中&#xff0c;波束成形&#xff08;Beamforming&#xff09;是一种通过调整天线阵列中各个阵元的信号相位和幅度&#xff0c;将电磁波能量集中在特定方向的技术。其核心目标是通过空间滤波增强目标方…

深圳漫云科技户外公园实景儿童剧本杀小程序:开启亲子互动新纪元

在亲子娱乐需求日益增长的当下&#xff0c;深圳漫云科技推出的户外公园实景儿童剧本杀小程序&#xff0c;凭借其创新玩法与丰富功能&#xff0c;为亲子家庭带来全新体验。该小程序融合户外探险、角色扮演与逻辑推理&#xff0c;不仅满足孩子好奇心&#xff0c;更提升其思维能力…

HOW - 如何测试 React 代码

目录 一、使用 React 测试库&#xff1a;testing-library/react二、使用测试演练场&#xff1a;testing-playground.com三、使用 Cypress 或 Playwright 进行端到端测试四、使用 MSW 在测试中模拟网络请求 一、使用 React 测试库&#xff1a;testing-library/react testing-li…

COBOL语言的网络安全

COBOL语言与网络安全&#xff1a;传统语言的新挑战 引言 COBOL&#xff08;Common Business-Oriented Language&#xff09;是一种早期编程语言&#xff0c;最初于1959年被开发出来&#xff0c;主要用于商业、金融和行政系统的处理。尽管年代久远&#xff0c;COBOL在大型机系…

通过世界排名第一的免费开源ERP,构建富有弹性的智能供应链

概述 现行供应链模式的结构性弱点凸显了对整个行业进行重塑的必要性。正确策略和支持可以帮助您重塑供应链&#xff0c;降低成本&#xff0c;实现业务转型。开源智造&#xff08;OSCG&#xff09;所推出的Odoo免费开源ERP解决方案&#xff0c;将供应链转化为具有快速响应能力的…

Android 开发中compileSdkVersion 和 targetSdkVersion

在 Android 开发中&#xff0c;compileSdkVersion 和 targetSdkVersion 是 build.gradle 文件中的两个关键配置&#xff0c;它们分别控制应用的编译行为和运行时兼容性。以下是它们的详细区别和用途&#xff1a; 1. compileSdkVersion&#xff08;编译版本&#xff09; 作用&a…

Qt QComboBox 下拉复选多选

Qt 中&#xff0c;QComboBox 默认只支持单选&#xff0c;但实际使用过程中&#xff0c;我们经常会碰到需要多选的情况&#xff0c;但是通过一些直接或者曲折的方法还是可以实现的。 1、通过 QListWidget 间接实现 这种方式是网上搜索最多的一种方式&#xff0c;也是相对来说比…

Selenium自动化:玩转浏览器,搞定动态页面爬取

嘿&#xff0c;各位爬虫爱好者和自动化达人们&#xff01;是不是经常遇到这种情况&#xff1a;信心满满地写好爬虫&#xff0c;requests一把梭&#xff0c;结果抓下来的HTML里&#xff0c;想要的数据空空如也&#xff1f;定睛一看&#xff0c;原来数据是靠JavaScript动态加载出…

天梯赛 L2-023 图着色问题

使用vector<vector<int>> g(N)去存储边&#xff0c;然后每次判断每个节点的邻节点是不是相同的颜色&#xff0c;需要注意的是不同的颜色一定需要为K种&#xff0c;不能多也不能少。 #include<bits/stdc.h> using namespace std; int main(){int n,m,k;cin&g…

在ubuntu24上装ubuntu22

实验室上有一台只装了ubuntu24的电脑&#xff0c;但是项目要求在22上进行 搞两个ubuntu系统&#xff01; 步骤一&#xff1a;制作22的启动盘 步骤二&#xff1a;进入bios安装界面 步骤三&#xff1a;选择try or install ubuntu 步骤四&#xff1a;选择try ubuntu 步骤五&…

【PVR Review】《Review of Deep Learning Methods for Palm Vein Recognition》

[1]谭振林,刘子良,黄蔼权,等.掌静脉识别的深度学习方法综述[J].计算机工程与应用,2024,60(06):55-67. 文章目录 1、Background and Motivation2、数据采集3、掌脉图像预处理3.1、ROI提取算法3.2、图像滤波与增强 4、掌脉识别算法4.1、基于深度学习的方法4.2、其他方法 5、融合识…

【CSP】202403-1词频统计

文章目录 算法思路1. 数据结构选择2. 输入处理3. 统计出现的文章数4. 输出结果 代码示例代码优化 样例输入 4 3 5 1 2 3 2 1 1 1 3 2 2 2 2 3 2样例输出 2 3 3 6 2 2算法思路 1. 数据结构选择 vector<int>&#xff1a;用于存储每篇文章的单词列表&#xff08;可能包含…

Docker基础1

本篇文章我将从系统的知识体系讲解docker的由来和在linux中的安装下载 随后的文章会介绍下载镜像、启动新容器、登录新容器 如需转载&#xff0c;标记出处 docker的出现就是为了节省资本和服务器资源 当企业需要一个新的应用程序时&#xff0c;需要为它买台全新的服务器。这样…

Linux系统学习Day04 阻塞特性,文件状态及文件夹查询

知识点4【文件的阻塞特性】 文件描述符 默认为 阻塞 的 比如&#xff1a;我们读取文件数据的时候&#xff0c;如果文件缓冲区没有数据&#xff0c;就需要等待数据的到来&#xff0c;这就是阻塞 当然写入的时候&#xff0c;如果发现缓冲区是满的&#xff0c;也需要等待刷新缓…

vue 3 从零开始到掌握

vue3从零开始一篇文章带你学习 升级vue CLI 使用命令 ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version ## 安装或者升级你的vue/cli npm install -g vue/cli ## 创建 vue create vue_test ## 启动 cd vue_test npm run servenvm管理node版本&#…

Mysql专题篇章

一、事务的四大特性&#xff1f; 1、原子性&#xff1a;是指事务包含的所有操作要么全部成功&#xff0c;要么全部失败回滚。 2、一致性&#xff1a;是指一个事务执行之前和执行之后都必须处于一致性状态。比如a与b账户共有100块&#xff0c;两人之间转账之后无论成功还是失败…

CAD插件实现:自动递增编号(前缀、后缀、位数等)——CADc#实现

cad中大量输入一定格式的递增编号时&#xff0c;可用插件实现&#xff0c;效果如下&#xff1a; ①本插件可指定数字位数、起始号码、加前缀、后缀、文字颜色等&#xff08;字体样式和文字所在图层为cad当前图层和当前字体样式&#xff09;。 ②插件采用Jig方式&#xff0c;即…

k8s1.24升级1.28

0、简介 这里只用3台服务器来做一个简单的集群&#xff0c;当前版本是1.24.17目标升级到1.28.17 地址主机名192.168.160.40kuber-master-1192.168.160.41kuber-master-2192.168.160.42kuber-node-1 因为1.24已经更换过了容器运行时&#xff0c;所以之后的升级相对就会简单&am…

4.3-2 jenkins

一.登录jenkins 二.修改密码 三.配置节点 新建节点 编辑节点名称 编辑节点配置 激活节点 将jar下载到指定的路径 再到dos命令下的路径 E:\az\wx 执行 配置节点成功 四. 安全设置中&#xff0c;勾选代理 五.新建项目 编辑项目名称 编辑项目执行的 路径&#xff1a;C:\Users\Ad…

js对象与数组的互转

js对象与数组的互转 文章目录 js对象与数组的互转一、数组转对象1.使用forEach,for in,es6展开运算符,assign2. 使用 Object.fromEntries()3. 将数组转为键值对对象4. 使用 reduce()4. 数组元素为对象时提取属性 二、对象转数组1. 提取键/值/键值对2. 转换为特定结构的数组 三、…