stack,queue的模拟实现以及优先级队列

这篇博客用来记录stack,queue的学习。

stack的模拟实现

stack的模拟实现比较简单,先上代码

#pragma once
#include<vector>
#include<list>
#include<deque>
#include<iostream>
using std::deque;
using namespace std;namespace bit
{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;};
}

这里要提及的点是: 首先,看到模板类处传的默认参数是deque,<其实这里是容器适配器>
deque属于既包含vector的一些优点又有一些list的优点,但由于他样样通样样松导致他不被我们广泛使用,这里不对deque进行详细介绍。

queue的模拟实现

和stack的模拟实现类似,还是比较好写的,直接上代码:

#pragma once
#include<vector>
#include<list>
#include<deque>
#include<iostream>
using std::deque;
using namespace std;
namespace bit
{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;};
};

queue和stack对比起来,不同的点在于queue有了队头和队尾的区别。出现front和back访问队头和队尾的元素,而栈上是top获取栈顶元素。 队列在pop处是有差别的,queue的pop是对队头front进行删除。

接下来,介绍的才是重点:

优先级队列

优先级队列,就是我们对队列进行排序。 排序的过程类似于前面学过的堆,我们先来看几个操作。

template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:priority_queue();bool empty() {return c.empty();}size_t size(){return c.size();}const T& top() {return c[0];   // 这里我们默认用的容器是vector,因为我们后面都有进行排序,所以//c[0]就可以访问到第一个元素(最大或者最小根据所传类参数决定)}private:Container c;Compare comp;

上面代码有一个地方,可能会比较迷惑。 就是传参数后面有一个class Compare的东西。
这个东西有个名字,叫仿函数

仿函数是什么?

仿函数可以理解成对类对象进行了包装,使得类对象能够像函数一样去使用。 但本质是在类中进行了操作符的重载而实现一个类似于函数功能的作用。
那么,这里我们传入这个仿函数,在接下来插入或删除中就可以用上了!
了解了仿函数之后,我们再来看看优先级队列的插入和删除操作

插入操作,我们进行排序类似于堆,所以我们回忆一下大堆小堆的插入删除。
以前我们向上调整时,判断条件是对parent和child的值进行判断。
但如果我们改变排序的顺序,例如从升序改成降序,我们这里就可能有多处代码要改。那为了简便,我们有了仿函数的概念。
仿函数该怎么具体使用,让我们来看看:
首先,我们要明确的点是,之前说了,仿函数其实是一个类。我们用仿函数,是因为他里面通过运算符重载实现了我们想要的操作
那么这里我们先定义这样的两个类

    template<class T>class less    //这个类用来排大堆,要注意这个单词虽然翻译过来是小,//但我们这里用这个函数实现的结果是大堆{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class greater  //这个类用来排小堆{public:bool operator()(const T& x, const T& y){return x > y;}};

那么,我们了解这个点之后,我们再将他放入代码中,去实现push和pop操作
下面这块代码紧接上面的代码

template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:void Adjustup(size_t child){Compare com;  //这里很重要! 我们通过传入的Compare类创建了这样一个对象,//之后利用这个对象,去比较大小int parent = (child - 1) / 2;while (child > 0){//这里就是不同点了,我们通过传入两个参数来比较大小!!// 这里三种写法都是对的,上面两种采用的是匿名对象的方式, 但还是推荐使用第三种!//if(Compare().operator()(c[parent],c[child]))//if(Compare()(c[parent],c[child]))//if(c[parent]<c[child])   //以前我们的方法if (com(c[parent], c[child])) {swap(c[parent], c[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){c.push_back(x);Adjustup(c.size() - 1);  // 这里传参不要传错了,不然会出现问题}void Adjustdown(size_t parent){Compare com;int child = parent * 2 + 1;while (child < c.size()){if (child + 1 < c.size() && com(c[child],c[child + 1]))child = child + 1;if (com(c[parent], c[child])){swap(c[child], c[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(c[0], c[c.size() - 1]);c.pop_back();Adjustdown(0);}private:Container c;Compare comp;
};

可以看到,我们比较大小是直接通过对象,来充分使用operator()来比较大小,我们注意写好传入参数的先后顺序, 之后只需要控制传入的类类型就可以轻松控制排序。
接下来看看这段代码实现的结果吧!

void test1()
{// 用默认的less排降序(大堆)bit::priority_queue<int> pq1;pq1.push(10);pq1.push(20);pq1.push(30);pq1.push(40);while (!pq1.empty()){cout << pq1.top() << ' ';pq1.pop();}cout << endl;// 用greater排升序(小堆)bit::priority_queue<int, vector<int>, bit::greater<int>> pq2;pq2.push(10);pq2.push(20);pq2.push(30);pq2.push(40);while (!pq2.empty()){cout << pq2.top() << ' ';pq2.pop();}cout << endl;
}

在这里插入图片描述
接着,我们进行一下升级。 我们传入Date日期类类型,看看可不可以同样实现

对Date日期类进行排序

// 首先这一段是对Date类的操作
class Date
{
public:friend ostream& operator<<(ostream& _cout, const Date& d);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);}
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}template<class T>
class greater  //这个类用来排小堆
{public:bool operator()(const T& x, const T& y){return x > y;}
void test2()
{// 日期类进行排升序   bit::priority_queue<Date, vector<Date>, greater<Date>> pq;Date d1(2024, 4, 8);pq.push(d1);pq.push(Date(2024, 4, 10));pq.push({ 2024, 2, 15 });while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;

在这里插入图片描述
那么这依然是能实现的。

接下来有一个特殊情况,如果我们传入的是指针类型呢?那还能不能比较大小呢?

指针类型的比较大小

bit::priority_queue<Date*, vector<Date*>> pqptr;
pqptr.push(new Date(2024, 4, 14));
pqptr.push(new Date(2024, 4, 11));
pqptr.push(new Date(2024, 4, 15)); while (!pqptr.empty())
{cout << *(pqptr.top()) << " ";pqptr.pop();
}
cout << endl;  

很遗憾,这里并不能实现我们的效果。
因为如此,毕竟的是指针本身的大小, 而这个大小属于随机的,因此比较出来结果也会是个随机值。因此我们必须为此写一个指针解引用去比较的仿函数

在上一段代码前我们需要传入

// 这里没有给模版(template<>),所以后面调用这个类时,就不需要传入对应的类模板参数,
// 直接调用这个类就可以了
class GreaterPDate
{
public:bool operator()(const Date* p1, const Date* p2){return *p1 > *p2;    // 这里是大于,就是后面形成小堆,(这个类叫Greater)}
};bit::priority_queue<Date*, vector<Date*>, GreaterPDate> pqptr;
pqptr.push(new Date(2024, 4, 14));
pqptr.push(new Date(2024, 4, 11));
pqptr.push(new Date(2024, 4, 15));  
while (!pqptr.empty())
{cout << *(pqptr.top()) << " ";pqptr.pop();
}
cout << endl;

在这里插入图片描述
如此,我们才能保证每次比较的是指针解引用后的结果。这样才能稳定形成结果!
当然,这里我写的是升序的代码,老样子,把Greater改成less的代码,就是降序的了!

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

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

相关文章

PyTorch中Torch.arange()函数详解

函数原型 arange(start0, end, step1, *, outNone, dtypeNone, layouttorch.strided, deviceNone, requires_gradFalse) -> Tensor 用法 返回大小为的一维张量&#xff0c;其值介于区间 为步长等间隔取值 参数说明 参数类型说明startNumber起始值&#xff0c;默认值&…

【Python的魅力】:利用Pygame实现游戏坦克大战——含完整源码

文章目录 一、游戏运行效果二、代码实现2.1 项目搭建2.2 加载我方坦克2.3 加载敌方坦克2.4 添加爆炸效果2.5 坦克大战之音效处理 三、完整代码 一、游戏运行效果 二、代码实现 坦克大战游戏 2.1 项目搭建 本游戏主要分为两个对象&#xff0c;分别是我方坦克和敌方坦克。用户可…

告别盲目投放,Xinstall让App广告效果一目了然

在移动互联网时代&#xff0c;App广告的投放已经成为企业营销的重要手段。然而&#xff0c;广告主在投放广告后&#xff0c;如何有效追踪广告效果、衡量广告ROI&#xff0c;一直是困扰他们的难题。今天&#xff0c;我们就来聊聊Xinstall这家国内专业的App全渠道统计服务商&…

计算一个结构的平方

在行列可自由变换的平面上计算3a1*3a1 得到的结构应该有9个点&#xff0c;并且点的分布有3a1的特征 这个9点结构可以化简成 1 1 1 1 1 1 1 1 1 显然这个结构可以再次平方&#xff0c;得到 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 …

python:reportlab 生成pdf:基本用法。

1.首先&#xff0c;打开cmd&#xff0c;安装reportlab pip install -i https://pypi.tuna.tsinghua.edu.cn/simple reportlab #从清华镜像安装更快 然后就可以使用其基本用法。 from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvasdef genera…

小程序评分/关键词/UV优化助力小程序登顶

随着小程序市场的日益繁荣&#xff0c;小程序搜索排名优化成为了众多开发者关注的焦点。小程序搜索排名被很多因素影响着&#xff0c;关键词、评分还有uv&#xff08;授权&#xff09;等。在本文小柚和各位老板分享如何有效优化小程序搜索排名的经验。 一、关键词策略 关键词是…

Python | Leetcode Python题解之第55题跳跃游戏

题目&#xff1a; 题解&#xff1a; class Solution:def canJump(self, nums: List[int]) -> bool:n, rightmost len(nums), 0for i in range(n):if i < rightmost:rightmost max(rightmost, i nums[i])if rightmost > n - 1:return Truereturn False

Web3的可持续性:构建环境友好的去中心化系统

引言 随着全球对可持续发展和环境问题的日益关注&#xff0c;Web3技术作为一种新型的互联网模式&#xff0c;也开始受到社区和开发者的关注。但很少有人关注到Web3对环境可持续性的潜在影响。本文将探讨Web3如何构建一个环境友好的去中心化系统&#xff0c;以及这如何促进一个…

偏微分方程算法之五点菱形差分法

目录 一、研究目标 二、理论推导 三、算例实现 四、结论 一、研究目标 上个专栏我们介绍了双曲型偏微分方程的主要算法及实现。从今天开始&#xff0c;我们在新的专栏介绍另一种形式偏微分方程-椭圆型的解法。 研究目标选取经典的二维椭圆型方程&#xff08;也称泊松Poisso…

马斯克突击访华;谷歌 Python 基础团队全数被裁;丨 RTE 开发者日报 Vol.195

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

python基础学习之写入csv文件

前言 在Python编程中&#xff0c;经常会遇到要将数据存到csv文件中&#xff0c;今天来详细讲一下。 一.功能目的 将以下数据存到csv文件中。 data [ {name: Alice, age: 25, city: New York}, {name: Bob, age: 30, city: Los Angeles}, {name: Charlie, age: 35, city:…

DS:单链表的实现

欢迎各位来到 Harper.Lee 的编程学习小世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客 我将在这里分享我的学习过程等心得 创作不易&#xff0c;码字不易&#xff0c;兄弟们养成先赞后看的好习惯哦&#xff01; 想一同进步的uu&#xff0c;可以来后来找我哦&…

Selenium IDE 常见错误笔记

错误1&#xff1a;Failed:Exceeded waiting time for new window to appear 2000ms 这个错误通常出现在第一次运行时&#xff0c;有两个原因&#xff1a; Firefox阻止了弹出式窗口&#xff0c;在浏览器设置里允许这个操作即可。 有些网站设置了反扒机制&#xff0c;脚本运行…

解决Blender导出FBX文件到Unity坐标轴错误的问题

发现Blender的模型导入到Unity里面有问题,简单研究了下发现是坐标系不同,Unity使用的是左手坐标系,Blender使用的是右手坐标系 。 下面直接将如何解决 首先忽略Blender的右手坐标系以及Z轴朝上的事&#xff0c;依照unity坐标系情况修改模型物体的旋转&#xff0c;以Blender猴…

算法工程师——算法岗的分类及要求汇总

算法岗工程师 根据 Talent Seer 人才报告显示,全球 AI 从业者总人数约有 30 万,还是供不应求,其中 AI 技术专家(具有相关领域博士学位及 3 年以上工作经验的)约有 3.65 万。 简介 对于计算机专业的毕业生而言,算法岗基本上就是 「高薪」 的代名词。 在当今 IT 行业,算…

【城市】2023深圳市定居与生活相关政策(含租房、租车)

【城市】2023深圳市定居与生活相关政策&#xff08;含租房、租车&#xff09; 文章目录 一、户籍身份1、深圳市居住登记凭证、居住证&#xff08;点击就送&#xff09;2、深圳落户&#xff08;点击就送1&#xff09; 二、人才补贴人才引进补贴&#xff08;含应届生&#xff09;…

vue3左树的全选和反选

<el-input v-model"filterText" placeholder"" style"width: 48%"/><el-button type"primary" click"handleSearch" class"ml-2">查找</el-button><el-radio-group v-model"form.choic…

学习笔记:能量信号与功率信号(一)

目录 一、能量信号&#xff08;Energy Signal&#xff09; 二、功率信号&#xff08;Power Signal&#xff09; 三、信号关系图 四、总结 能量信号和功率信号是信号分析中两个基本的概念&#xff0c;它们主要用来描述信号在时间域中能量分布的特性&#xff0c;对于理解信号…

Faststone Capture:一触即发的效率革命【AI写作】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

苹果发布开源模型;盘古大模型5.0将亮相;英伟达将收购 Run:ai

苹果首次发布开源语言模型 近期&#xff0c;苹果在 Hugging Face 发布了 OpenELM 系列模型。OpenELM 的关键创新是逐层扩展策略&#xff0c;该策略可在 transformer 模型的每一层中有效地分配参数&#xff0c;从而提高准确性。 与具有统一参数分配的传统语言模型不同&#xff…