1. 前言
主要分为两部分
1.priority_queue的作用: 实现 大顶堆,小顶堆,本文主要就该容器的使用方法和如何定义第三个模板参数进行详解,需要读者对模板、函数指针、函数对象(仿函数)有一定了解,当然也有对函数指针和函数对象的区别作简单介绍。
2. 第二种库函数方法实现大小顶堆:vector、make_heap、push_heap、pop_heap组合使用,
·
2.1 priority_queue函数原型解析
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
class priority_queue
这是
priority_queue
的底层代码,如是指定第一个参数的类型,后面两个模板参数都会有默认形式,如,priority_queue<int>
,第二个模板参数默认取vector<int>
类型,第三个默认取less<int>
类型(less底层是一个结构体)。然而本文重点是第三个参数的制定。
2.2 priority_queue的使用方法介绍
priority_queue和队列基本操作相同:关于怎么操作请参考,不是本文重点。
top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容
创建priority_queue的三种不同方式:
1.第一种:只定义一个参数,默认形式下,这里是一个关于字符串的大顶堆(按字符串的第一个字符排,最大的在堆顶)
priority_queue<string> pq;//也可以是 int,char等
2.第二种:改变第三个模板参数实现小顶堆解析,需要注意的是,为什么这里不是sort(v.begin(),v.end(),less<int>())
那样调用函数对象 加括号() 呢:因为sort
这里第三个参数是是传实参,为函数对象或者函数指针,这里的less<int>()
是一个函数对象,less
结构体的operator()
函数。而priority_queue
在创建的时候是指定模板参数,也就是指定参数的类型,所以是使用less<int>
,告诉priority_queue
第三个模板的参数类型是一个less<int>
类,不加()。函数对象其实也是一种函数指针,但是两者之间的区别我有作简单的介绍,足够理解本文。
priority_queue<int,vector<int>,less<int>> pq;
·
3. 第三种:当第一个模板参数是自定义数据时,就需要自定义一个比较方式,可以是一个比较类(需要重载(),以调用函数对象),可以是一个函数指针(一般采用lamda表达式,因为它需要使用当前函数的传入参数,但又不能在函数体内定义函数,故采用这样的方式)。
1)采用类作为第三个模板参数。指定第三个模板参数是cmp
类型,不能是cmp()
函数对象(仿函数)。
struct Node{//也可以是class
int x,y;
Node(int a=0, int b=0):
x(a), y(b) {}
};
struct cmp{//也可以是class
bool operator()(Node a, Node b){
if(a.x == b.x) return a.y>b.y;
return a.x>b.x; //>实现小顶堆,<实现大顶堆
}
};
int main(){
priority_queue<Node, vector<Node>, cmp>p;
for(int i=0; i<10; ++i)
p.push(Node(rand(), rand()));
while(!p.empty()){
cout<<p.top().x<<' '<<p.top().y<<endl;
p.pop();
}//while
//getchar();
return 0;
}
·
·
2)采用函数指针作为第三个模板参数。这里以leetcode剑指offerII 061
的题解代码为例,实现第三个参数为函数指针的priority_queue
。而这里采用lamda表达式,因为它需要用到kSmallestPairs
的参数,而不写在函数体外。然后重点来了,需要结合decltype(cmp)
和 pq(cmp)
的使用方式(具体原理不清楚)。个人理解是声明cmp函数(实际是以指针)为一个指针类,从而作为模板参数,并在命名的时候使用pq(cmp),把函数指针cmp作为参数初始化pq。
同时说明cmp
在>下实现小顶堆,<实现大顶堆,理解就是后面来的数据在符号右边,如>,它小就返回true,让后面进来的数和前面的数换位置,实现小顶堆。
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k){
auto cmp=[&](const pair<int, int>& lhs, const pair<int, int>& rhs){
return nums1[lhs.first] + nums2[lhs.second] > nums1[rhs.first] + nums2[rhs.second];
//当后面进来下标pair对rhs下:nums1[rhs.first] + nums2[rhs.second]小时,将这个rhs和lhs置换,实现小顶堆
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);
}
2.3 总结
如果还是不理解可以结合下面几篇高访文章理解,或留言评论区,当然我也是初出茅庐,如有不对之处还望请大佬指出。
https://blog.csdn.net/weixin_36888577/article/details/79937886
[https://blog.csdn.net/xiaoquantouer/article/details/52015928?]
3.1 make_heap等组合实现大小顶堆的方法
vector
、make_heap
、push_heap
、pop_heap
的各功能如代码里面的注释所示
大顶堆的实现:第三个参数默认是less<int>()
函数对象。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(int argc, char const *argv[]) {
int myints[] = {10,20,30,5,15}; // fixed-size array
vector<int> v(myints, myints+5); // convert to vector
make_heap(v.begin(), v.end()); // make max heap from range
cout << "initial max heap : " << v.front() << "\n"; // heap top
pop_heap(v.begin(), v.end()); // move heap top to the end
v.pop_back(); // pop/remove back the last element
cout << "max heap after pop : " << v.front() << "\n";
v.push_back(99); // insert an element to the end
push_heap(v.begin(), v.end()); // rearrange elements to form a heap
cout << "max heap after push: " << v.front() << "\n";
cout << "max heap range :";
for (int i = 0; i < v.size(); i++) {
cout << " " << v[i];
}
cout << "\n";
return 0;
}
大顶堆的结果为:
initial max heap : 30
max heap after pop : 20
max heap after push: 99
max heap range : 99 20 10 5 15
··········································································································································································
实现小顶堆:更改第三个参数为greater<int>()
//make_heap组合使用实现小顶堆
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int myints[] = { 10,20,30,5,15 }; // fixed-size array
vector<int> v(myints, myints + 5); // convert to vector
make_heap(v.begin(), v.end(),greater<int>()); // make min heap from range
cout << "min heap range :";
for (int i = 0; i < v.size(); i++) {
cout << " " << v[i];
}cout << "\n";
cout << "initial min heap : " << v.front() << "\n"; // heap top
pop_heap(v.begin(), v.end(), greater<int>()); // move heap top to the end,and make min heap from range except the last element
cout << "min heap range after pop_heap:";
for (int i = 0; i < v.size(); i++) {
cout << " " << v[i];
}cout << "\n";
v.pop_back(); // pop/remove back the last element
cout << "min heap after pop : " << v.front() << "\n";
v.push_back(99); // insert an element to the end
push_heap(v.begin(), v.end()); // rearrange elements to form a heap
cout << "min heap after push: " << v.front() << "\n";
cout << "min heap range :";
for (int i = 0; i < v.size(); i++) {
cout << " " << v[i];
}cout << "\n";
system("pause");
return 0;
}
大顶堆结果为:
min heap range : 5 10 30 20 15
initial min heap : 5
min heap range after pop_heap: 10 15 30 20 5
min heap after pop : 10
min heap after push: 99
min heap range : 99 10 30 20 15