C++ priority_queue
文章目录
前言
prionrity_queue 被称为优先队列,但它的底层其实是用堆来实现的,并且因为 prionrity_queue 的底层为堆,所以其队首元素一定为当前队列中优先级最高的一个。
一、priority_queue的定义
如果要使用优先队列,应该添加头文件,声明命名空间 std
#include <queue>
using namnespace std;
priority_queue定义方式
1.使用默认的优先级
当优先队列中使用的是如 int、 double、 char等基本的数据类型时,其优先级是根据优先队列中元素的大小有关,默认为数字越大的优先级越高(如果为 char 类型,则是 字典序 越大的优先级越高)
使用默认优先级的优先队列如下:
#include <queue>
using namespace std;
priority_queue<typename> MyP_Q; //typename 为任意数据类型或容器
2.使用自定义的优先级
当需要自定义优先队列的优先级时,需要在定义中多加两个参数,一个用于确定承载底层数据结构堆的容器,另一个用来确定优先级的大小顺序。
自定义优先级的优先队列如下:
请仔细阅读注释
#include <queue>
using namespace std;
//这了定义了一个 int 型且数字大的优先级大的优先队列
priority_queue<int, vector<int>, less<int> > MyP_Q;
//第二个参数 vector<int> 是承载底层堆的容器,因为第一个参数类型为 int 所以这里为 vector<int>
//如果第一个参数为 double 则承载底层堆的容器为 vector<double> 以此类推
//第三个参数 less<int> 是对第一个参数的比较类,也就是用来定义 优先级顺序的
//less<int> 表示数字大的优先级大, greater<int> 表示数字小的优先级越大
//如果第一个参数为 double 则第三个参数为 less<double> 或者 greater<double> 以此类推
二、priority_queue常用函数
1.push(a):令 a 元素入队;top():访问队首元素
push() 时间复杂度为 O(logN), N为当前队列中元素个数
top() 时间复杂度为 O(1)
注意:
1.在每次 push() 入元素时,优先队列的底层 堆 都会进行调整,使得队首元素为优先级最高元素
2.priority_queue 中没有 front() 和 back() 这两个函数,其只能通过 top() 访问元素
代码如下(示例):
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int> MyP_Q;
int main()
{
MyP_Q.push(1);
MyP_Q.push(9);
MyP_Q.push(5);
cout << MyP_Q.top() << endl; //因为 push() 时会把优先级最高的放在队首,所以这里应该是 9
return 0;
}
结果如下:
2.pop():令队首元素出队(删除队首元素)
时间复杂度为O(logN),N为当前优先队列中元素个数
代码如下(示例):
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int> MyP_Q;
int main()
{
MyP_Q.push(5);
MyP_Q.push(8);
MyP_Q.push(2);
cout << MyP_Q.top() << endl; //此时优先级最高元素为 8
MyP_Q.pop(); //删除优先级最高元素 8 后优先级最高元素应该为 5
cout << MyP_Q.top() << endl;
return 0;
}
结果如下:
3.empty():检测优先队列是否为空,为空返回true,非空返回false
时间复杂度 O(1)
代码如下(示例):
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int> MyP_Q;
//判断优先队列是否为空,为空返回false。非空返回true
bool IsNotEmpty(priority_queue<int> a)
{
if(a.empty()) return false; //根据empty()先判断 if语句是否为真,如果为真,函数返回 false
else return true;
}
int main()
{
if(IsNotEmpty(MyP_Q)) cout << "T" << endl;
else cout << "F" << endl;
MyP_Q.push(2);
if(IsNotEmpty(MyP_Q)) cout << "T" << endl;
else cout << "F" << endl;
return 0;
}
结果如下:
4.size():返回有点队列中元素个数
时间复杂度 O(1)
代码如下(示例):
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int> MyP_Q;
int main()
{
MyP_Q.push(1);
cout << MyP_Q.size() << endl;
MyP_Q.push(2);
cout << MyP_Q.size() << endl;
return 0;
}
结果如下:
三、priority_queue内元素为结构体的优先级设置
1.直接定义的结构体类型优先队列
如果想直接定义结构体类型的优先队列,则需要用到友元函数,并重载小于号 **“ < ”**通过该友元函数的返回值来确定优先级先后顺序。
为什么需要友元:因为在本结构体里面重载的二元运算符时, 只需要一个参数,另一个参数由this指针传入,这里如果需要传入两个参数,需要放到结构体外定义(下方已介绍),声明友元。
示例如下(数字大的优先级大):
#include <iostream>
#include <queue>
using namespace std;
struct test{
int test_id;
int test_score;
friend bool operator < (test s1, test s2)
{
return s1.test_score < s2.test_score;
//重载小于号后功能还是小于号
//由于优先队列默认为大顶堆,所以重载过后是数字大的优先级大
//如果 返回值为 s1.test_score > s2.test_score 则数字小的优先级大
}
};
int main()
{
priority_queue<test> MyP_Q;
test s1, s2, s3;
s1.test_id = 1;
s1.test_score = 10;
s2.test_id = 2;
s2.test_score = 20;
s3.test_id = 3;
s3.test_score = 30;
MyP_Q.push(s2);
MyP_Q.push(s3);
MyP_Q.push(s1);
cout << MyP_Q.top().test_id << " " << MyP_Q.top().test_score << endl;
return 0;
}
结果如下
2.自定义的结构体类型优先队列
自定义的结构体类型优先队列说白了就是使用非友元函数的方式即为:自己在结构体外面定义一个结构体的比较规则(类似于 sort 中的 cmp,只不过效果与 cmp 相反),然后用多参数的优先队列定义方式将比较规则传入,最终完成优先队列的构造
示例如下(数字大的优先级大):
#include <iostream>
#include <queue>
using namespace std;
struct test
{
int test_id;
int test_score;
};
//以下为自定义的比较规则
struct cmp
{
bool operator () (test s1, test s2)
{
return s1.test_score < s2.test_score;
// 返回值是小于号时,数字大的优先级高
// 返回值是大于号时,数字小的优先极高
}
}
/
int main()
{
test s1, s2, s3;
priority_queue<test, vector<test>, cmp> MyP_Q; //该定义方式见本章第一节第2点
s1.test_id = 1;
s1.test_score = 10;
s2.test_id = 2;
s2.test_score = 20;
s3.test_id = 3;
s3.test_score = 30;
MyP_Q.push(s2);
MyP_Q.push(s3);
MyP_Q.push(s1);
cout << MyP_Q.top().test_id << " " << MyP_Q.top().test_score << endl;
return 0;
}
结果如下: