C++容器适配器的模拟实现-stack、queue、priority_queue
###
容器适配器是将容器转换到其他容器自身不方便使用的地方,但是就容器适配器其本身还是包装的容器,所以这个类模板中各个接口的实现都是调用的容器的接口,因为容器适配器可能适配多个容器,所以这个类模板的模板参数中有一个参数是代表容器类型的,方便传参过来能及时改变;
一、stack的模拟
这是这个类模板的模板,那么我们也模拟这样实现,首先解读,T是stack里面存放的数据类型,Container是stack里面包装的容器的类型,默认是deque,这是因为deque这个容器不仅兼顾了vector和list的基本接口,并且deque相比于vector不需要浪费过多空间、头删头插的效率高,相比于list的缓存利用率更高,这个和deque的底层结构有关;
###stack实现的代码:
#pragma once
#include<deque>
#include<list>
#include<vector>
using namespace std;
namespace S
{template<class T,class Container = deque<T>>class Stack{public:Stack()//调用Container的默认构造函数{}bool empty()const{return _con.empty();}size_t size()const{return _con.size();}const T& top()const{return _con.back();}void push(const T& val = T()){_con.push_back(val);}void pop(){_con.pop_back();}private:Container _con;};
}
首先stack对于vector、list、deque都能作为它们的适配器,所以头文件包含了这几个容器;
其次看到这个模板类的成员变量,是一个Container,代表容器类型,这个容器类型默认为deque,用这个类型去定义一个容器作为stack这个适配器的成员变量,那么在实现stack的接口时,就直接调用容器_con的接口;
###测试:
void test1()
{Stack<int> st;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);cout << "数据个数:" << st.size() << endl;cout << "是否为空:" << st.empty() << endl;cout <<"栈顶数据:" << st.top() << endl;st.pop();cout << "数据个数:" << st.size() << endl;cout << "栈顶数据:" << st.top() << endl;
}
注意在源文件中测试时要包含实现stack的头文件,并且展开命名空间;
###运行结果:
二、queue的模拟
和stack大差不差,注意它不能作为vector的适配器,队列queue的头删(出队列)的接口要调用pop_front,而vector没有这个接口,所以不能;
###代码:
namespace Q
{template<class T ,class Container = deque<T>>class Queue{public:Queue(){}bool empty()const{return _con.empty();}size_t size()const{return _con.size();}const T& front()const{return _con.front();}const T& back()const{return _con.back();}void push(const T& val=T()){_con.push_back(val);}void pop(){_con.pop_front();}private:Container _con;};
}
###测试:
void test2()
{Queue<int> q;for (int i = 1; i <= 5; i++){q.push(i);}cout << "是否为空:" << q.empty() << endl;cout << "数据个数:" << q.size() << endl;cout << "队头数据:" << q.front() << endl;cout << "队尾数据:" << q.back() << endl;q.pop();//删除队头数据cout << "队头数据:" << q.front() << endl;
}
注意Queue<int> q;可以显示传它的容器类型,stack也是一样;
###运行结果:
三、priority_queue的模拟
这个是优先级队列,它的其他地方和queue一样,就是队头的元素一直是最大的或者是最小的,它的底层实现有堆的部分,大堆的堆顶也就是最大的,小堆的相反;所以在实现时涉及到堆的向上和向下调正的方法;
另外,我们要写一份类模板,这个类模板要求可以通过接收不同的模板参数来调正这个优先级队列是通过大堆实现的还是通过小堆实现的 ,这也是库里面的实现方法;也就是说,这个适配器的模板参数中要包含一个类型,这个类型实例化出来的对象作为适配器的成员变量(和_con类似),并且这个对象可以调用自己的函数来实现更大或者更小的比较,这里需要使用仿函数;
所谓的仿函数就是重载()的函数;
直接看实现的代码来解读
###代码实现:
namespace Q
{
//仿函数重载()template<class T>class Less{public:bool operator()(T& x, T& y){return x < y;}};template<class T>class Greater{public:bool operator()(T& x, T& y){return x > y;}};template<class T,class Container =vector<T>,class Compare = Less<T>>class Priority_Queue{public:Priority_Queue(){}bool empty()const{return _con.empty();}size_t size()const{return _con.size();}const T& top()const{return _con[0];}void AdjustUp(){int child = _con.size() - 1;int parent = (child - 1) / 2;while (child >= 0){if(_com(_con[parent],_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& val = T()){_con.push_back(val);AdjustUp();//向上调正建堆}void AdjustDown(){int parent = 0;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])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){assert(_con.size());swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown();}private:Container _con;Compare _com;//调用仿函数就直接_com(),相当于_com.operator();};}
第二个模板参数是vector这是因为里面有top的接口,而vector也有;
首先看到类Less和Greater,里面有成员函数,都是重载的()的函数,也就是仿函数,包装成一个类是因为类可以作为类型传到模板参数中;
看到优先级队列的类模板的实现,第三个模板参数就是上面封装的类,这个默认是Less,在看到优先级队列的成员变量,除了我们已近知道的_con,还有一个_com,这是通过Less实例化出来的对象,这个对象可以直接在后面加上()来调用它自己的成员函数,那么就可以来进行比较了;
其他的接口很平常,看到push和pop的接口,首先push,要进行向上调整,里面使用_com(),就是比较父节点和子节点,父节点更小就和子节点交换,实现大堆;pop删除是先交换队头和队尾的数据再pop_back(),相当于删除了队头的节点,之后再进行向下调整,把次大的换到根节点处;
只有涉及到父节点和子节点比较大小时才用到_com(),这是因为这个函数的比较决定了是大堆还是小堆,当传Less<T>时就是大堆;传Greater时就是小堆(把更大的换到了子节点);
###测试:
void test3()
{Priority_Queue < int,vector<int>> pq;pq.push(1);pq.push(2);pq.push(3);pq.push(4);pq.push(5);pq.pop();cout << "是否为空:" << pq.empty() << endl;cout << "数据个数:" << pq.size() << endl;cout << "队头数据:" << pq.top() << endl;//也是堆顶数据
}
###运行结果
push走完
pop走完
可以观察到这就是按照堆的规则调整的;
相关文章:

C++容器适配器的模拟实现-stack、queue、priority_queue
### 容器适配器是将容器转换到其他容器自身不方便使用的地方,但是就容器适配器其本身还是包装的容器,所以这个类模板中各个接口的实现都是调用的容器的接口,因为容器适配器可能适配多个容器,所以这个类模板的模板参数中有一个参数…...

fastapi的docs页面是空白解决
环境:openEuler、python 3.11.6、fastapi 0.115.2 背景:居家办公,默认搭建的fastapi的docs接口为空白 时间:20241016 说明:网上很多教程的缺点是复杂(但是能够了解的更清楚),使用…...

浙大数据结构:11-散列4 Hashing - Hard Version
这道题主要在于思路,感觉像个模拟题,用到了线性探测的算法 机翻 1、条件准备 visit数组看这个位置有没有放进来数,num存非负整数,s存未到放入时机的数。 answer存答案。n为总共数量。 #include <iostream> #include<…...
pm2 守护http-server
PM2(Process Manager 2)是一个用于Node.js应用程序的进程管理器。以下是使用PM2守护HTTP服务器的步骤: 1. 安装PM2 如果你还没有安装PM2,可以使用以下命令安装: npm install pm2 -g 2. 启动HTTP服务器 你需要一个HTT…...

国外电商系统开发-运维系统应用管理
还记得您常用的 service httpd start 、service sshd stop这样的命令吗?这些都是在停止启动服务,为了让研发人员,或者是快速操作服务,这里给大家制定了简单的应用管理。在这里,您可以把上面的命令加入进来,…...

剖析线程池实现原理
前置推荐阅读:java并发之线程池使用-CSDN博客 自定义实现一个带监控的线程池 首先我们继承ThreadPoolExecutor,实现构造函数以及重写beforeExecute和afterExecute两个函数,具体调用我们会在代码实现层面进行详细的分析。 import java.util.…...

【中危】Oracle TNS Listener SID 可以被猜测
一、漏洞详情 Oracle 打补丁后,复测出一处中危漏洞:Oracle TNS Listener SID 可以被猜测。 可以通过暴力猜测的方法探测出Oracle TNS Listener SID,探测出的SID可以用于进一步探测Oracle 数据库的口令。 建议解决办法: 1. 不应该使…...

三维测量与建模笔记 - 简介
计算机视觉相关主题 主要有两个最主要的层面,几何和语义。几何层面描述了客观事实,比如物体的距离、大小、形状、位置等。语义层面则是从人类抽象出的概念出发,描述了物体是什么、行为是什么、为什么,比如自动驾驶场景中识别出信号…...
Glide 简易教程
文章目录 1 引入依赖2 图片形状2.1 圆形 CircleCrop2.2 旋转 Rotate2.3 圆角 RoundedCorners2.4 自定义圆角 GranularRoundedCorners 1 引入依赖 implementation("com.github.bumptech.glide:glide:4.16.0")2 图片形状 2.1 圆形 CircleCrop Glide.with(this).load…...

flutter 使用三方/自家字体
将字体放入assets/fonts下 在pubspec.yaml文件中flutter下添加如下代码: flutter:fonts:- family: MyCustomFontfonts:- asset: assets/fonts/MyCustomFont.ttf 在flutter Text widget中使用字体 import package:flutter/material.dart;void main() > runApp(…...

2024台州赛CTFwp
备注: 解题过程中,关键步骤不可省略,不可含糊其辞、一笔带过。解题过程中如是自己编写的脚本,不可省略,不可截图(代码字体可以调小;而如果代码太长,则贴关键代码函数)。…...

词根plac-和place、please
英文有一个词根和单词place(v.放,放置 n.位置,地方;位,职位)长得很像,这个词根就是plac-,它有两个语义:高兴,愉悦;平静,抚平。 其实,place这个单…...

ubuntu下route命令详解
buntu下route命令详解 1、显示路由表 route -n2、临时路由设置,重启网卡失效#添加一条路由(发往192.168.62这个网段的全部要经过网关192.168.1.1)route add -net 192.168.62.0 netmask 255.255.255.0 gw 192.168.1.1#删除一条路由 删除的时候不用写网关route del …...
13.java面向对象:面向对象的三大特征
java面向对象:面向对象的三大特征 面向对象的三大特征1.封装get和set规范属性的合法化 2.继承类继承子类调用父类方法super的用法通过super调用父类public的属性super注意点super对比this 方法重写静态方法中奇怪的现象非静态方法 3.多态多态存在的条件多态中成员访…...
【VUE】Vue中的内置组件
Vue2中的内置组件: <component>:动态组件,可以根据传递的 is 属性值渲染不同的组件。<transition>:过渡动画组件,可以在元素插入、更新或移除时添加动画效果。<transition-group>:过渡动…...

若依框架篇-若依框架搭建具体过程、后端源代码分析、功能详解(权限控制、数据字典、定时任务、代码生成、表单构建、接口测试)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 若依框架概述 1.1 若依构建 1.2 后端项目搭建 1.3 前端项目搭建 2.0 利用若依框架生成前后端代码案例 3.0 功能详解 3.1 功能详解 - 权限控制 3.1.1 使用权限控制…...

恢复已删除文件的 10 种安卓数据恢复工具
由于我们现在在智能手机上存储了大量重要文件,因此了解数据恢复工具变得很重要。您永远不会知道什么时候需要使用 安卓 数据恢复工具。 由于不乏 Windows 数据恢复工具,因此从崩溃的计算机中恢复文件很容易。但是,当涉及到从 安卓恢复数据时…...

Internet Download Manager2025快速下载,新功能解锁!
🌟下载界的“速度与激情”:Internet Download Manager超燃体验!🔥 嘿,各位小伙伴们!👋今天我要来给你们安利一个让我上网冲浪效率翻倍的神奇软件——Internet Download Manager(简称…...
传感器应用注意事项
一、通断型传感器 多数活动部件可直接作为导电材料的传感器为通断型传感器,在受力的条件下,其两个引脚的通断状态会发生改变。 常见通断型传感器 单通道按键多通道按键拨码开关接线帽磁力开关轻触开关… 通断型传感器无需供电,其控制环路…...

PayPal美区账号注册指南
PayPal作为一种便捷的在线支付方式,受到了广大用户的青睐。特别是对于那些需要在美国购物或者进行交易的人来说,注册并正确使用美国地区的PayPal账户显得尤为重要。本次小编会教大家如何注册和使用美区PayPal账户,并讨论是否需要“养号”的问…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...