总结
1)优先队列,首先他是个队列,第二 有优先级,内部是堆维护,出队顺序可以为优先级从大到下 或者从小到大。
2)定义
priority_queue q;
priority_queue, less > q;
第2个参数是用来盛放堆的容器, 第三个参数决定优先级
less 越来越小, greater 越来越大。
3)结构体定义定义 ,可以重载运算符,
重运算符写到结构体内
struct fruit{
string name;
int price;
friend bool operator < (fruit f1, fruit f2){
return f1.price < f2.price;
}
};
prioritt_queue q;
写到结构体外
struct cmp {
bool operator () (fruit f1, fruit f2){
return f1.price < f2.price;
}
};
priority_queue, cmp> q;
加速度 + const + &
friend bool operator < (const fruit &f1, const fruit &f2){
return f1.price > f2.price;
}
bool operator()(const fruit &f1, const fuit &f2){
return f1.price > f2.price;
}
4)使用top() 函数前,必须用 empty()判断优先队列是否为空,否则可能因为队空出错
贴两篇大佬的文章:
坐在马桶上看算法_堆_优先队列(上)
坐在马桶上看算法_堆_优先队列(下)
什么是priority_queue?
priority_queue 又称为优先队列,底层是用堆来实现的,在优先队列中队首元素一定是当前队列中优先级最高的那一个,
桃子(优先级3)
梨子(优先级4)
苹果(优先级1)
出队顺序为 梨子(4)-》桃子(3) -》苹果(1)
当染我们可以在任何时候往优先队列里加入元素(push)。而优先队列底层的数据结构堆(heap)会随时进行调整,(优先队列里有一个堆,每次插入元素,这个堆就会自动调整),使得每次的队首元素都是优先级最大的。
优先队列的应用
1)定义
要使用优先队列,应先添加头文件
#include
using namespace std;
其他写法给其他容器相同
priority_queue< typename > name;
2)priority_queue容器内元素的访问
和队列不一样的是,优先队列没有front()函数与back()函数,而只能通过top()函数来访问队首元素,(也可以说是堆顶元素)也就是优先级最高的元素。
#include
#include
using namespace std;
int main (){
priority_queue< int > q;
q.push(3);
q.push(4);
q.push(1);
cout << q.top() << endl;
return 0;
}
他原本的优先级就是从大到小,也就是说他本来堆是一个大顶堆。
常用函数
1)push()
push(x)令x入队,时间复杂度,为O(logN),其中N为当前优先队列中的元素的个数,
2)top()
top()可以获得队首元素(堆顶元素)时间复杂度为 O(1)
3)pop()
pop()令队首元素出队,时间复杂度为O(logN),其中N为当前优先队列中元素的个数。
#include
#include
using namespace std;
int main (){
priority_queue< int > q;
q.push(3);
q.push(4);
q.push(1);
cout << q.top() << endl;
q.pop();
cout << q.top() << endl;
return 0;
}
4)empty()
判空,若是空返回true,非空返回false。时间复杂度为O(1)。
5)size()
返回优先队列中元素的个数,时间复杂度为O(1)
priority_queue内元素的优先级的设置
就是 int double, char等可以直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级最高,一次队首元素就是队列内元素最大那个(如果是char型,则字典序中最大的)。对基本数据类型来说,下面两种定义等价
priority_queue q;
priority_queue, less > q;
可以发现,第二种定义方式尖括号内多了两个参数,一个是 vector
如果想让优先队列总是把最小的元素放在队首只需要进行以下定义
priority_queue, greater > q;
下面例子
#include
#include
using namespace std;
int main (){
priority_queue, greater > q;
q.push(3);
q.push(4);
q.push(1);
cout << q.top() << endl;
q.pop();
cout << q.top() << endl;
return 0;
}
最开始我们是不是看到一个水果的优先级定义
struct fruit{
string name;
int price;
};
现在我们希望按照水果的价格大小进行排序。
第一步我们需要 重载 < 。重载的意思就是对已有的运算符进行重新定义,就是说可以改变 < 的功能。
struct fruit{
string name;
int price;
friend bool operator < (fruit f1, fruit f2){
return f1.price < f2.price;
}
};
我们在结构体内增加了一个函数,其中:friend 为友元友元函数大家可以百度一下,简单
函数重载
后面的 " bool operator < (fruit f1, fruit f2) " 对fruit类型的操作符,“ < " 进行了重载,(重载大于号编译器会出错,因为从数学来说只需要重载小于号,即 f1 > f2 等价与判断 f2 < f1 ,而f1 == f2 则等价与判断 ! (f1< f2) && ! (f1 > f2))
这样我们就可以直接定义一个优先队列
priority_queue q;
如果想以价格低的受过为优先级高则进需要把 return中的 小于号 改为 > 即可
struct fruit{
string name;
int price;
friend bool operator < (fruit f1, fruit f2){
return f1.price > f2.price;
}
};
例子
#include
#include
#include
using namespace std;
struct fruit{
string name;
int price;
friend bool operator < (fruit f1, fruit f2){
return f1.price < f2.price;
}
}f1, f2, f3;
int main (){
priority_queue q;
f1.name = "桃子";
f1.price = 3;
f2.name = "梨子";
f2.price = 4;
f3.name = "苹果";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
诶诶诶诶,我好像发现了什么。这个对与 < 号的重载 好像和 sort中的cmp函数有些相似,他们的参数都是两个变量,函数内部都是return 了 true 或者 false.但是 效果好像正好相反,若果是 cmp 中 return < 号,那就是从小到大排列,其实在重载 < 号时也是这样,但是 优先队列定义后就直接相反了,因为优先队列本身默认规则就是优先级高的放在最前,不好记?
优先队列中的这个函数 与 sort中的cmp 函数的效果是相反的
那么可以跟sort中的cmp 写到结构体外呢? 当然OK
struct cmp {
bool operator () (fruit f1, fruit f2){
return f1.price < f2.price;
}
};
这种情况下我们就需要用之前定义优先队列的第二种方式 定义优先队列。
priority_queue, cmp> q;
我们只是把 greater<> 换成了 cmp
#include
#include
#include
using namespace std;
struct fruit{
string name;
int price;
}f1, f2, f3;
struct cmp {
bool operator () (fruit f1, fruit f2){
return f1.price < f2.price;
}
};
int main (){
priority_queue, cmp> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "梨子";
f2.price = 4;
f3.name = "苹果";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
同样,即便是基本数据类型或者其他STL容器,如(set), 也可以通过同样的方式来定义优先级
最后指出数据如果结构体内数据庞大,建议使用引用来提高效率。+ 上 “const ” 和 “&”
friend bool operator < (const fruit &f1, const fruit &f2){
return f1.price > f2.price;
}
bool operator()(const fruit &f1, const fuit &f2){
return f1.price > f2.price;
}