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.xdnf.cn/news/141680.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

S09-录入的数据快速分列

选中某一列数据&#xff0c;数据-》分列 确定分隔符

Blender导出FBX给UE5

最近在学习UE5的资源导入&#xff0c;总结如下&#xff1a; 建模使用Blender&#xff0c;UE5版本是5.3 1.纯静态模型导入UE5 Blender FBX导出设置保持默认即可&#xff0c; UE5把导入设置里Miscellaneous下Force Front XAxis和Convert Scene Unit勾选即可 2.带骨骼动画的模型…

命令执行(rce)

1.命令与代码执行原理 命令执行原理 参数给变量未经过滤&#xff0c;直接使用了不安全的函数处理了变量 127.0.0.1&&ipconfig 有漏洞 常用的函数 assert,system,exec,shell_exec, eval,(反单引号&#xff09; 代码执行原理 参数给变量未经过滤&#xff…

Postgresql源码(113)表达式JIT计算简单分析

相关 《Postgresql源码&#xff08;85&#xff09;查询执行——表达式解析器分析&#xff08;select 11如何执行&#xff09;》 《Postgresql源码&#xff08;113&#xff09;表达式JIT计算简单分析》 1 普通表达式计算 普通表达式计算发生在优化器preprocess_expression中&am…

Day1-DeepWalk

论文《DeepWalk: Online Learning of Social Representations》 2014年发表在数据挖掘顶会ACM SIGKDD&#xff08;KDD&#xff09;上的论文 目的&#xff1a;学习节点表示 推动&#xff1a;将自然语言处理里面的无监督学习方法迁移至此 思路&#xff1a;将图结构序列化&#x…

关于安卓SVGA浅尝(二)加载数据

关于安卓SVGA浅尝&#xff08;二&#xff09;加载数据 相关链接 SVGA官网 SVGA-github说明文档 背景 项目开发&#xff0c;都会和动画打交道&#xff0c;动画的方案选取&#xff0c;就有很多选择。如Json动画&#xff0c;svga动画&#xff0c;gif等等。各有各的优势。目前项…

【Linux】系统编程基于环形队列生产者消费者模型(C++)

目录 【1】引入POSIX信号量 【1.1】初始化信号量 【1.2】销毁信号量 【1.3】等待信号量 【1.4】发布信号量 【2】基于环形队列的生产消费模型 【2.1】生产消费模型打印数字模型 【2.2】生产消费模型计算公式模型 【2.3】生产消费模型计算公式加保存任务模型 【1】引入…

React中setState的原理及深层理解

1.为什么使用setState React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化 我们必须通过setState来告知React数据已经发生了变化 setState方法是从Component中继承过来的。 2.setState异步更新 setState设计为异步&#xff0c;可…

深度学习技巧应用28-强化学习的原理介绍与运用技巧实践

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用28-强化学习的原理介绍与运用技巧实践, 强化学习是一种机器学习的子领域,它使得一个智能体在与环境的交互中学习如何行动以最大化某种数值奖励信号。强化学习模型的关键特性是它的试错搜索和延迟奖励。 一、强化学习…

聚势共创 多元共生——中科美菱联动清华大学助力产研融合!

9月23日&#xff0c;由中科美菱首席赞助支持的第十六届清华大学“生命科学、医学、药学”博士生学术论坛在美丽的白洋淀畔——雄安新区拉开序幕。清华大学生物物理学家、中国科学院院士隋森芳、清华大学生命科学学院党委书记吴畏、雄安新区党工委员会委员、管委会副主任丁晓龙、…

Windows下创建后门隐藏用户的常见方法

文章并没有什么技术含量,纯粹是我正好在做这个事情,同时想到自己之前没有写过,所以特意写一遍记录以下 windows 下的后门用户主要分为以下4种。 启用游客用户创建普通用户创建普通隐藏用户创建影子用户 第一种启用游客用户 通过以下命令即可启用Guest用户&#xff0c;该用户是…

怎么将aac转换成mp3格式?

怎么将aac转换成mp3格式&#xff1f;AAC&#xff08;它的全称为Advanced Audio Coding&#xff09;是一种高级音频编码格式。它采用了数字音频压缩算法&#xff0c;旨在提供更高的音频质量和更低的比特率。AAC和Mp3一样都是一种有损压缩算法&#xff0c;通过移除人耳无法察觉的…

PostgreSql 统一修改date字段为timestamp

在《Powdersigner PostgreSql 同步表结构到pg数据库》中&#xff0c;导入表结构到pg数据后&#xff0c;发下时间对不上了。mysql的datetime转换后pg的变成了date了。 再同步到数据后&#xff0c;就变成日期类型了。 因为表中基本都有创建时间和修改时间&#xff0c;两个相对固…

IDEA新建.xml文件显示为普通文本

情况如下&#xff1a; 1. 在XML文件中添加*.xml的文件名模式 2. 在文本中&#xff0c;选中*.xml进行删除

Linux 进程层次分析

Linux 进程组 每个进程都有一个进程组号 (PGID) 进程组&#xff1a;一个或多个进程的集合 (集合中的进程并不孤立)进程组中的进程通常存在父子关系&#xff0c;兄弟关系&#xff0c;或功能相近 进程组可方便进程管理 (如&#xff1a;同时杀死多个进程&#xff0c;发送一个信…

ChatGPT AIGC 非常实用的AI工具集合大全

实战AI 工具箱 AIGC ChatGPT 职场案例60集, Power BI 商业智能 68集, 数据库Mysql8.0 54集 数据库Oracle21C 142集, Office, Python ,ETL Excel 2021 实操,函数,图表,大屏可视化 案例实战 http://t.csdn.cn/zBytu

云安全之访问控制介绍

访问控制技术背景 信息系统自身的复杂性、网络的广泛可接入性等因素&#xff0c;系统面临日益增多的安全威胁&#xff0c;安全问题日益突出&#xff0c;其中一个重要的问题是如何有效地保护系统的资源不被窃取和破坏。 访问控制技术内容包括访问控制策略、访问控制模型、访问…

SpringBoot @value注解动态刷新

参考资料 Spring系列第25篇&#xff1a;Value【用法、数据来源、动态刷新】【基础系列】SpringBoot配置信息之配置刷新【基础系列】SpringBoot之自定义配置源的使用姿势【基础系列】SpringBoot应用篇Value注解支持配置自动刷新能力扩展Spring Boot 中动态更新 Value 配置 一. …

什么记事本软件记录恋爱时间准确?恋爱时间计时器app有哪些?

对于很多情侣来说&#xff0c;恋爱的每一天都值得记录。所以在恋爱期间&#xff0c;情侣对恋爱天数的记录充满了浪漫和纪念的意义。记录每一天&#xff0c;不仅是对爱情的见证&#xff0c;更是对彼此之间承诺的延续。不过情侣想要记录恋爱天数&#xff0c;就需要先找到一款恋爱…

C++实现nms和softmax

最近在面试过程中遇到了手写nms的问题&#xff0c;结束后重新实现并调通了nms和softmax的代码。 1、NMS 原理&#xff08;通俗易懂&#xff09;&#xff1a; 先假设有6个候选框&#xff0c;根据分类器类别分类概率做排序&#xff0c;从小到大分别属于车辆的概率分别为A、B、C、…