C++:优先级队列模拟实现和仿函数的概念使用

文章目录

  • 使用方法
  • Compare仿函数
  • 一些场景
  • 模板参数和函数参数

本篇总结优先级队列

使用方法

首先在官网查看它的一些用法

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

从它的介绍可以看出,也是一个用到了容器适配器的容器,这里不同于stackqueue的适配器,这里使用的是vector作为它的适配器,也是用了模板来实例化,但是多了一个Compare的概念,关于Compare后面来引入

具体用法:

Priority queue
Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be retrieved (the one at the top in the priority queue).

Priority queues are implemented as container adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements. Elements are popped from the “back” of the specific container, which is known as the top of the priority queue.

The underlying container may be any of the standard container class templates or some other specifically designed container class. The container shall be accessible through random access iterators and support the following

从上面的英文中可以很明显的获取到信息,它的用法和堆非常类似,因此对应的接口设计也很像,下面用实验来简单使用一下
在这里插入图片描述

#include <iostream>
#include <queue>
using namespace std;int main()
{priority_queue<int> pq;pq.push(3);pq.push(2);pq.push(1);pq.push(4);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}return 0;
}

上面是对优先级队列的简单使用,从中可以看出,在队列中添加了3,2,1,4四个元素,但是最后输出的确实4,3,2,1,证明它确实是和堆是一样的,那么基于这个原理就可以对它进行模拟实现了,具体实现如下:

// Version1--初级版本
#include <iostream>
#include <vector>
using namespace std;namespace my_priority_queue
{template<class T, class Container = vector<int>>class priority_queue{public:bool empty(){return _con.empty();}size_t size(){return _con.size();}const T& top(){return _con.front();}void adjust_up(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);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(int parent){int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child + 1] > _con[child]){child++;}if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}private:Container _con;};
}

整体来说实现难度不大,只是需要对于向上和向下调整算法要熟悉,有了这两个算法解决问题并不难,但是这样的实现虽然可以适配前面的测试用例,但是并不是库内实现的方法,库内的实现还有一个Compare的概念

Compare仿函数

对于库内的函数,只能实现降序排序,很明显库内不可能只支持降序输出,那么如何控制降序输出?

库中定义的仿函数默认是less,与之对应的还有greater,如果使用greater就将是升序输出:

int main()
{priority_queue<int,vector<int>,less<int>> pq1;pq1.push(3);pq1.push(2);pq1.push(1);pq1.push(4);cout << "降序排列:" << endl;while (!pq1.empty()){cout << pq1.top() << " ";pq1.pop();}cout << endl;priority_queue<int, vector<int>, greater<int>> pq2;pq2.push(3);pq2.push(2);pq2.push(1);pq2.push(4);cout << "升序排列:" << endl;while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}cout << endl;return 0;
}// 输出结果
降序排列:
4 3 2 1
升序排列:
1 2 3 4

那么这个lessgreater到底是什么?由此引出下面仿函数的概念

在前面实现的Version1的实现中,并没有实现这个功能,这是由于在建堆的时候,建立的是大堆还是小堆已经限定了,但是在实际的应用中这里不应该被限定,应该根据实际情况创建对应的堆,但是代码逻辑只能根据大于和小于来判断,由此引出可以使用仿函数来实现这个功能

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;}
};

上面就是对于仿函数的定义,其实从中可以看出仿函数其实就是一个只有一个函数的类,里面定义了运算符重载,而当程序执行到需要进行比大小的时候,就可以借助这个运算符重载得出结论,进而执行,这样就实现了改变大小于关系的函数

根据这个原理,就可以实现下面的过程:

// Version2
// 头文件
#include <iostream>
#include <vector>
using namespace std;namespace my_priority_queue
{template<class T, class Container = vector<int>, class Compare = Less<class T> >class priority_queue{public:bool empty(){return _con.empty();}size_t size(){return _con.size();}const T& top(){return _con.front();}void adjust_up(int child){Compare com;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& x){_con.push_back(x);adjust_up(_con.size() - 1);}void adjust_down(int parent){Compare com;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(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}private:Container _con;};
}

// main.c文件
#include <iostream>
#include <queue>
#include "priority_queue.h"
using namespace std;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;}
};void test1()
{my_priority_queue::priority_queue<int, vector<int>, Less<int>> pq1;pq1.push(3);pq1.push(2);pq1.push(1);pq1.push(4);cout << "降序排列:" << endl;while (!pq1.empty()){cout << pq1.top() << " ";pq1.pop();}cout << endl;my_priority_queue::priority_queue<int, vector<int>, Greater<int>> pq2;pq2.push(3);pq2.push(2);pq2.push(1);pq2.push(4);cout << "升序排列:" << endl;while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}cout << endl;
}int main()
{test1();return 0;
}

具体的指向演示如下:

在这里插入图片描述

一些场景

其实仿函数的应用场景很多,这里说比较基础的场景

例如算法库中存在的sort排序函数,其实也是有仿函数的存在的

template <class RandomAccessIterator>void sort (RandomAccessIterator first, RandomAccessIterator last);template <class RandomAccessIterator, class Compare>void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

于是可以利用这些函数实现效果

void test2()
{Less<int> com;int arr[] = { 7,6,5,4,3,9,8,6 };int sz = sizeof(arr) / sizeof(arr[0]);sort(arr, arr + sz, com);for (auto ch : arr){cout << ch << " ";}cout << endl;Greater<int> comp;sort(arr, arr + sz, comp);for (auto ch : arr){cout << ch << " ";}cout << endl;
}

模板参数和函数参数

对比模板参数和函数参数:

// 模板参数
template<class T, class Container = vector<int>, class Compare = Less<class T> >
my_priority_queue::priority_queue<int, vector<int>, Greater<int>> pq;// 函数参数
sort(arr, arr + sz, Less<int>());

对于这里需要注意的是,模板参数内传的是类的名字,而函数传参传的是对象,因此上面的写法其实是匿名对象的写法

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

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

相关文章

【RabbitMQ实战】05 RabbitMQ后台管理

一、多租户与权限 1.1 vhost的概念 每一个 RabbitMQ服务器都能创建虚拟的消息服务器&#xff0c;我们称之为虚拟主机(virtual host),简称为 vhost。每一个 vhost本质上是一个独立的小型RabbitMQ服务器&#xff0c;拥有自己独立的队列、交换器及绑定关系等&#xff0c;并且它拥…

Pycharm2023版修改镜像源

步骤1 步骤2 国内常见镜像源 阿里云 http://mirrors.aliyun.com/pypi/simple/中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/豆瓣(douban) http://pypi.douban.com/simple/清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/中国科学技术大学 http://pypi.mirrors.…

腾讯mini项目-【指标监控服务重构】2023-08-29

今日已办 Collector 指标聚合 由于没有找到 Prometheus 官方提供的可以聚合指定时间区间内的聚合函数&#xff0c;所以自己对接Prometheus的api来聚合指定容器的cpu_avg、cpu_99th、mem_avg 实现成功后对接小组成员测试完提供的时间序列和相关容器&#xff0c;将数据记录在表格…

01 MIT线性代数-方程组的几何解释

一, 线性方程的几何图像 The geometry of linear equations 线性代数的基本问题就是解n元一次方程组 eg&#xff1a;二元一次方程组 矩阵形式: 系数矩阵(coefficient matrix): 未知数向量: 线性方程组简记为Axb 二, 行图像 Row Picture 行图像遵从解析几何的描述&#xff0…

离散小波变换(概念与应用)

目录 概念光伏功率预测中,如何用离散小波变换提取高频特征概念 为您简单地绘制一些示意图来描述离散小波变换的基本概念。但请注意,这只是一个简化的示意图,可能不能完全捕捉到所有的细节和特性。 首先,我将为您绘制一个简单的小波函数和尺度函数的图像。然后,我会提供一…

放弃webstrom转战vscode

本来是webstrom的忠实用户&#xff0c;无奈webstrom要么需要在网上找一个破解版或者不断的去找激活码&#xff0c;且破解版和激活码的文章总是很多&#xff0c;但是要找到真正有效的却总是要花费不少功夫。终于忍无可忍&#xff0c;转战vscode。&#xff08;注&#xff1a;文中…

SpringBoot全局异常处理源码

SpringBoot全局异常处理源码 一、SpringMVC执行流程二、SpringBoot源码跟踪三、自定义优雅的全局异常处理脚手架starter自定义异常国际化引入封装基础异常封装基础异常扫描器&#xff0c;并注册到ExceptionHandler中项目分享以及改进点 一、SpringMVC执行流程 今天这里叙述的全…

华为OD机考算法题:分积木

目录 题目部分 解读与分析 代码实现 题目部分 题目分积木难度难题目说明Solo和koko是两兄弟&#xff0c;妈妈给了他们一大堆积木&#xff0c;每块积木上都有自己的重量。现在他们想要将这些积木分成两堆。哥哥Solo负责分配&#xff0c;弟弟koko要求两个人获得的积木总重量“…

ROS2 从头开始:第 08/8回 - 使用 ROS2 生命周期节点简化机器人软件组件管理

一、说明 欢迎来到我在 ROS2 上的系列的第八部分。对于那些可能不熟悉该系列的人,我已经涵盖了一系列主题,包括 ROS2 简介、如何创建发布者和订阅者、自定义消息和服务创建、

LLM - Make Causal Mask 构造因果关系掩码

目录 一.引言 二.make_causal_mask 1.完整代码 2.Torch.full 3.torch.view 4.torch.masked_fill_ 5.past_key_values_length 6.Test Main 三.总结 一.引言 Causal Mask 主要用于限定模型的可视范围&#xff0c;防止模型看到未来的数据。在具体应用中&#xff0c;Caus…

Unity之Hololens开发如何实现UI交互

一.前言 什么是Hololens? Hololens是由微软开发的一款混合现实头戴式设备,它将虚拟内容与现实世界相结合,为用户提供了沉浸式的AR体验。Hololens通过内置的传感器和摄像头,能够感知用户的环境,并在用户的视野中显示虚拟对象。这使得用户可以与虚拟内容进行互动,将数字信…

内存对齐--面试常问问题和笔试常考问题

1.内存对齐的意义 C 内存对齐的主要意义可以简练概括为以下几点&#xff1a; 提高访问效率&#xff1a;内存对齐可以使数据在内存中以更加紧凑的方式存储&#xff0c;从而提高了数据的访问效率。处理器通常能够更快地访问内存中对齐的数据&#xff0c;而不需要额外的字节偏移计…

Learn Prompt- Midjourney 图片生成:Image Prompts

Prompt 自动生成 前不久&#xff0c;Midjourney 宣布支持图片转 prompt 功能。 原始图片​ blueprint holographic design of futuristic Midlibrary --v 5Prompt 生成​ 直接输入 /describe 指令通过弹出窗口上传图像并发送&#xff0c;Midjourney 会根据该图像生成四种可…

完成“重大项目”引进签约,美创科技正式落户中国(南京)软件谷

近日&#xff0c;美创科技正式入驻中国&#xff08;南京&#xff09;软件谷&#xff0c;并受邀出席中国南京“金洽会"之“雨花台区数字经济创新发展大会”。美创科技副总裁罗亮亮作为代表&#xff0c;在活动现场完成“重大项目”引进签约。 作为国家重要的软件产业与信息服…

关于ubuntu设置sh文件开机自启动python3和sudo python3问题

关于ubuntu设置sh文件开机自启动python3和sudo python3问题 说明系统为 ubuntu22.04python是python3.10.12ros系统为ros2 humble 背景解决方法补充 说明 系统为 ubuntu22.04 python是python3.10.12 ros系统为ros2 humble 背景 将一个py文件设置为开机自启动&#xff0c;服…

贪心算法总结归类(图文解析)

贪心算法实际上并没有什么套路可言&#xff0c;贪心的关键就在于它的思想&#xff1a; 如何求出局部最优解&#xff0c;通过局部最优解从而推导出全局最优解 常见的贪心算法题目 455. 分发饼干 这题的解法很符合“贪心”二字 如果使用暴力的解法&#xff0c;那么本题是通过…

Windows--Python永久换下载源

1.新建pip文件夹&#xff0c;注意路径 2.在上述文件中&#xff0c;新建文件pip.ini 3.pip.ini记事本打开&#xff0c;输入内容&#xff0c;保存完事。 [global] index-url https://pypi.douban.com/simple

【记录文】Android自定义Dialog实现圆角对话框

圆角的dialog还是蛮常用的&#xff0c;demo中正好用上了 自定义Dialog&#xff0c;代码中可以设置指定大小与位置 /*** author : jiangxue* date : 2023/9/25 13:21* description :圆角的矩形*/internal class RoundCornerView(context: Context,view: Int, StyleRes theme…

开机自启动Linux and windows

1、背景 服务器由于更新等原因重启&#xff0c;部署到该服务上的响应的应用需要自启动 2、Linux 2.1 方式一 编写启动应用的sh脚本授权该脚本权限 chmod 777 xxx.sh 修改rc.loacl 位置&#xff1a;/etc/rc.local 脚本&#xff1a;sh /home/xxxx.sh & 授权rc.local …

Elasticsearch—(MacOs)

1⃣️环境准备 准备 Java 环境&#xff1a;终端输入 java -version 命令来确认版本是否符合 Elasticsearch 要求下载并解压 Elasticsearch&#xff1a;前往&#xff08;https://www.elastic.co/downloads/elasticsearch&#xff09;选择适合你的 Mac 系统的 Elasticsearch 版本…