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,一经查实,立即删除!

相关文章

Mac 通过 brew安装的 ffmpeg 切换版本

现有版本为 6.x &#xff0c;想切换至 5.x 版本 先安装 5.x 版本 brew install ffmpeg5安装完成后会出现具体版本号&#xff0c;也可以自己指定例如 brew install ffmpeg5.1.3 配置环境变量 .zshrc vi ~/.zshrc添加如下命令 export PATH/usr/local/Cellar/ffmpeg5/5.1.3/bin:…

【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.…

C# 删除文件夹

要在 C# 中删除文件夹&#xff0c;您可以使用 http://System.IO 命名空间中的 Directory.Delete 方法。以下是一个示例代码&#xff0c;演示如何删除一个文件夹&#xff1a; using System; using System.IO;class Program {static void Main(){string folderPath "C:\Pa…

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

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

linux的三剑客

1、grep命令 grep全称是Global Regular Expression Print&#xff0c;表示全局正则表达式版本&#xff0c;它的使用权限是所有用户。它是Linux系统中一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&#xff0c;并把匹配的行打印出来。 shell脚本中也经常使用g…

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;文中…

2023.9 - MYSQL - 基础命令

DATABASE 1、创建数据库 - - create database 【mydatabase】&#xff1b; 2、删除数据库 - - drop database 【mydatabase】&#xff1b; 3、切换数据库 - - use 【mydatabase】&#xff1b; -------------------------------------------------…

SpringBoot全局异常处理源码

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

linux 下 top命令显示的是内存是堆内存吗?

top 命令在 Linux 下提供了关于系统运行状态的实时视图&#xff0c;其中包括进程信息、CPU 使用率、内存使用情况等。关于内存&#xff0c;top 命令显示的并不是“堆内存”&#xff0c;而是整个系统的内存使用情况。 在 top 命令的输出中&#xff0c;你会看到类似以下的内存统…

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

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

Android 11.0 增加多张图片作为系统静态壁纸的功能实现

1.前言 在11.0的系统开发中,在做系统定制化开发中,在对系统的静态壁纸做定制的时候,需要增加几种静态壁纸可以让用户自己设置壁纸,所以可以在壁纸的系统应用中 添加几种静态壁纸图片,然后配置好 就可以在选择壁纸的时候,作为静态壁纸,接下来看如何具体实现这个功能 2.增…

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;而不需要额外的字节偏移计…

libevent学习——辅助类型和函数

辅助类型和函数 文章目录 基本类型evutil_socket_t标准整数类型各种兼容性类型 定时器可移植函数套接字 API 兼容性可移植的字符串操作函数区域无关的字符串操作函数IPv6辅助和兼容性函数结构体可移植性函数安全随机数发生器 <event2/util.h>定义了很多在实现可移植应用…

Learn Prompt- Midjourney 图片生成:Image Prompts

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