这里先简单介绍一下优先级队列priority_queue:优先队列是一种容器适配器,默认的情况下,如果没有为特定的priority_queue类实例化指容器类,则使用vector (deque 也是可以的),需要支持随机访问迭代器,以便始终在内部保持堆结构

文章目录

  • 一、使用
  • 二、仿函数
  • 三、模拟实现
    • 1、基础接口
    • 2、push与向上调整
    • 3、pop与向下调整
    • 4、构造函数
    • 5、总体代码

一、使用

在有了前面容器使用的基础之下,我们对于优先级队列priority_queue的使用成本不是很大,值得注意的是头文件为

普通的队列是先进先出,优先级队列默认是优先级高的先出

Container:优先级队列默认使用vector作为其底层存储数据的容器,支持[]的使用,支持随机访问,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。

Compare:注意:默认情况下priority_queue是大堆,仿函数为less。

构造函数

接口

查看文档的接口

常用接口

函数声明 接口说明
priority_queue()/priority_queue(first, last) 构造一个空的优先级队列
empty( ) 检测优先级队列是否为空,是返回true,否则返回 false
top( ) 返回优先级队列中最大(最小元素),即堆顶元素
push(x) 在优先级队列中插入元素x
pop() 删除优先级队列中最大(最小)元素,即堆顶元素

直接进入代码环节:

1.默认情况下,priority_queue是大堆

2.想让priority_queue是小堆:greater,头文件为functional

到了这里,我们发现priority_queue的使用并不难,下面,我们通过一道题目来看看priority_queue的妙处把:

  1. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

直接排序是O(NlogN),这个地方既可以建大堆也可以建小堆:建n个数的大堆,建堆是O(n),然后在pop K次,即O(N+k*logN),缺陷在于N太大。建K个数的小堆,剩下的数进一个数据与堆顶做比较,大的进堆,最终第K大的就是堆顶,建K个数的小堆为O(K),故时间复杂度为O(K+(N-K)*logK),当N远大于K是建议采用第二种。

第一种:建n个数的大堆

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//建大堆priority_queue<int> pq(nums.begin(),nums.end());//前k-1个popwhile(--k){pq.pop();}return pq.top();}
};

第二种:建K个数的小堆

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//前k个数建小堆priority_queue<int,vector<int>,greater<int>>pq(nums.begin(),nums.begin()+k);for(size_t i =k;i<nums.size();i++){if(nums[i]>pq.top()){pq.pop();pq.push(nums[i]);}}return pq.top();}
};

我们可以发现在有了优先级队列之后我们对于这道题的解法大大简便了。不用像之前一样去自己手动实现一个堆了。


二、仿函数

仿函数/函数对象也是类,是一个类对象。仿函数要重载operator(),我们直接自己来通过代码来看一看仿函数:

namespace hwc
{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;}};}
int main()
{hwc::less<int> lessFunc;lessFunc(1, 2);return 0;
}
//lessFunc是一个对象,仿函数对象,可以像函数一样使用

仿函数的作用在于:在C语言中我们通过传入函数指针解决升序降序问题,虽然C++兼容了C,但是C++并没有继续利用函数指针,而是通过仿函数来控制升序和降序,我们直接以之前写过的排序为例子,通过利用仿函数来实现升序和降序

template<class T,class Compare>
void BubbleSort(T* a, int n, Compare com)
{for (int j = 0; j < n; j++){int exchange = 0;for (int i = 1; i < n - j; i++){//if (a[i]<a[i-1])if (com(a[i], a[i-1])){swap(a[i - 1], a[i]);exchange = 1;}}if (exchange == 0){break;}}
}
int main()
{hwc::less<int> lessFunc;hwc::greater<int> greaterFunc;lessFunc(1, 2);int a[] = { 2,3,4,5,6,1,2,8 };BubbleSort(a, sizeof(a) / sizeof(int),lessFunc);for (auto e : a){cout << e << " ";}cout << endl;BubbleSort(a, sizeof(a) / sizeof(int), greaterFunc);for (auto e : a){cout << e << " ";}cout << endl;return 0;
}

传值传参问题:这里是直接传值传参Compare com,当然也可以传引用传参const Compare& com,不过要记得加上const进行修饰,另外一般的仿函数比较小,问题不是很大。

自定义类型
这里的比较大小是比较常见的,如果是自定义类型:

比如日期类,那该如何去进行大小的比较?一种是重载大小的比较运算符,使之支持日期类的大小比较。另一种是可以自己定义仿函数专门去进行日期类的大小比较

1.重载运算符

比较大小需要我们自己去重载>,<,<<,这些在日期类的时候我们就详细的说过了,直接来看代码:

#include <iostream>
#include <queue>
#include <functional>
#include <algorithm>
#include <vector>using namespace std;
class Date
{
public: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);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};
void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载priority_queue<Date> q1;q1.push(Date(2018, 10, 29));q1.push(Date(2018, 10, 28));q1.push(Date(2018, 10, 30));cout << q1.top() << endl;// 如果要创建小堆,需要用户提供>的重载priority_queue<Date, vector<Date>, greater<Date>> q2;q2.push(Date(2018, 10, 29));q2.push(Date(2018, 10, 28));q2.push(Date(2018, 10, 30));cout << q2.top() << endl;
}
int main()
{TestPriorityQueue();
}

2.定义仿函数

如果传入的是Date*指针,此时上面的运算符重载已经不符合我们的需求了,比较的是地址的大小,但是我们要比较的是日期的大小,所以我们通过自己定义仿函数的方式来实现我们的需求:

class Date
{
public: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);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};struct PDateLess
{bool operator()(const Date* d1, const Date* d2){return *d1 < *d2;}
};struct PDateGreater
{bool operator()(const Date* d1, const Date* d2){return *d1>*d2;}
};
void TestPriorityQueue()
{//大堆priority_queue <Date*, vector<Date*>, PDateLess> q3;q3.push(new Date(2018, 10, 29));q3.push(new Date(2018, 10, 28));q3.push(new Date(2018, 10, 30));cout << *q3.top() << endl;//小堆priority_queue<Date*, vector<Date*>, PDateGreater> q4;q4.push(new Date(2018, 10, 29));q4.push(new Date(2018, 10, 28));q4.push(new Date(2018, 10, 30));cout << *q4.top() << endl;
}

最终顺利完成:

有了上面的知识内容之后,下面我们进入的是优先级队列priority_queue的模拟实现!

【C++】优先级队列priority_queue仿函数相关推荐

  1. 【C++】优先级队列priority_queue/仿函数(函数对象)

    这里写目录标题 一.优先级队列 1.优先级队列的介绍 2.priority_queue的定义与使用 二.仿函数/函数对象 三.优先级队列的模拟实现 一.优先级队列 1.优先级队列的介绍 1)注意优先级 ...

  2. 6-5-3:STL之stack和queue——优先级队列-priority_queue(堆)的基本使用和模拟实现以及仿函数

    文章目录 一:优先级队列-priority_queue(堆) (1)基本使用 (2)模拟实现 二:仿函数 (1)仿函数是什么 (2)使用仿函数完成大顶堆和小顶堆的构建 一:优先级队列-priority ...

  3. 优先级队列priority_queue

    优先级队列priority_queue 优先级队列是一个拥有权值的queue,其内部元素按照元素的权值排列.权值较高者排在最前优先出队.其中缺省情况下系统是通过一个max-heap以堆实现完成排序特性 ...

  4. STL学习系列七:优先级队列priority_queue容器

    1.简介 最大值优先级队列.最小值优先级队列 优先级队列适配器 STL priority_queue 用来开发一些特殊的应用,请对stl的类库,多做扩展性学习 这里给个例子: #include< ...

  5. C++ STL 学习笔记__(6)优先级队列priority_queue基本操作

    10.2.7优先级队列priority_queue v  最大值优先级队列.最小值优先级队列 v  优先级队列适配器 STL priority_queue v  用来开发一些特殊的应用,请对stl的类 ...

  6. (P85)stl(十三):容器适配器,stack,queue,优先级队列priority_queue,make_heap

    文章目录 1.容器适配器 2.stack 3.queue 4.优先级队列priority_queue 5.make_heap 6.set 1.容器适配器 利用基本容器构造的容器,称之为容器适配器 基本 ...

  7. 详解优先级队列priority_queue(应用+模拟实现)

    优先级队列的概念 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元 素 ...

  8. C++ 优先级队列 priority_queue

    优先级队列(priority_queue)是一种容器适配器(container adaptor).它要求容器具有front.push_back.pop_back等操作,并且容器具有随机访问的能力,故优 ...

  9. STL之优先级队列priority_queue

    摘要: priority_queue,自适应容器(即容器适配器):不能由list来组建: 最大值优先级队列(最大值始终在对首,push进去时候) 最小值优先级队列: 优先级队列适配器 STL  pri ...

最新文章

  1. WinJS实用开发技巧(3):仿微博信息流JK快捷键滚动
  2. mysql 外键引擎_对于mysql的外键和mysql的存储引擎
  3. java pom.xml 自定义变量
  4. 【Android 高性能音频】OboeTester 音频性能测试应用 ( Oboe 输出测试参数 | API 选择 | 音频输出设备选择 | 采样率 | 通道 | 采样格式 | 播放偏好 )
  5. 下列哪个是java的标识符_下列哪个不属于Java的正确标识符?A、publicB、sizeofC、cLAssD、_new...
  6. Vim编辑器的基本使用和三种模式
  7. mysql中jdbc的metadata_JDBC(九)DatabaseMetaData 数据库元数据
  8. Map的Value值转换为List集合
  9. ​Hmily重启后月度报告
  10. 如何使用_如何使用Excel播放音乐
  11. 什么是git_什么是Git?
  12. 每日三道前端面试题--vue 第三弹
  13. duilib绝对定位与相对定位
  14. 我的游记--九色甘南 扎尕那
  15. 小程序 界面响应速度优化
  16. Riverbed助力富邦人寿在市场竞争和数字化进程中抢占先机
  17. django-模板语言-verbatim标签-不使用DTL的解析
  18. 团队合作开发的两种文档工具
  19. APP测试基础--小工具介绍(1)
  20. 无线蓝牙耳机那个品牌比较好?试试这五款比较实用的吧

热门文章

  1. python奇数阶乘求和_使用Python阶乘求和的方法及问题总结
  2. Python计算阶乘(5种方法)
  3. Qt - QSetting的使用
  4. node.js sream II
  5. 地心直角坐标系转经纬高
  6. java基础学习笔记(四、常用基础类)
  7. 【游戏】PC游戏引擎简介及游戏使用技术检测技巧
  8. MATLAB sub2ind函数的使用
  9. dl dt 对比 tr td
  10. 浅谈GWAS分析后的富集分析操作(GO/KEGG)