优先级队列priority_queue
包含头文件< queue>
priority_queue的介绍
引用《STL源码剖析》中对priority_queue的介绍,priority_queue是一个拥有权值观念的queue,由于这是一个queue,所以只允许在底端加入元素,从顶端取出元素,其内的元素并非依照被推入的次序排列,而是自动依照元素的权值排列(通常权值以实值表示)。
优先级队列,一种容器适配器,在全缺省情况下,使用vector作为其底层容器,又使用堆算法将vector中元素构造成堆结构,因此priority_queue默认是大堆。
priority_queued的使用
priority_queue的模板参数
T:元素类型;
Container:封装的底层容器;
Compare:比较器;
priority_queue的常用函数
构造
priority_queue<int> fst; //构造空优先级队列
priority_queue<int> trd(first(), last()); //用迭代器构造优先级队列
priority_queue<int> fou(fst); //拷贝构造
判空
fst.empty(); //为空返回true,否则返回false
元素个数
fst.size(); //返回元素个数
堆顶元素
fst.top(); //返回对堆顶元素的引用
插入
fst.push(2);
push函数会调用底层容器对象的push_back函数,然后调用push_heap算法将新插入元素重新排序。
删除
fst.pop();
删除优先级队列的堆顶元素,pop函数会调用pop_heap算法保留优先级队列的堆属性,调用底层容器对象的pop_back函数删除元素。这将调用被移除元素的析构函数。
priority_queue的定义
#include<queue>
#include<vector>
#include<functional> //greater算法的头文件
#include<iostream>
using namespace std;
void test_priority_queue(){
vector<int> v{ 8, 6, 4, 0, 3, 9, 2 };
//默认情况下创建的是大堆,其底层按照小于号比较
priority_queue<int> q1;
for (auto& e : v)
q1.push(e);
//如果要创建小堆,将模板中的比较器改为greater比较方式
//如果要在priority_queue中放置自定义类型,需要在自定义类型中提供 < 或 > 的重载
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
}
priority_queue的模拟实现
namespace test{
template<class T>
struct less{
bool operator()(const T& left, const T& right){
return left < right;
}
};
template<class T>
struct greater{
bool operator()(const T& left, const T& right){
return left > right;
}
};
template<class T, class Container = vector<T>,class Compare = less<T>>
class priority_queue{
public:
priority_queue(){} //构造空优先级队列
template<class Iterator>
priority_queue(Iterator first, Iterator last) //迭代器构造优先级队列
:c(first, last){
//把c中的元素调整具有大堆的性质
int count = c.size() - 1;
int root = ((count - 1) >> 1);
for (; root >= 0; --root){
DownwardMove(root);
}
}
void push(const T& val){
c.push_back(val); //尾插,向上调整-该结点与父亲结点比较调整
if (c.size() == 1)
return;
UpwardMove(c.size() - 1); //参数是结点下标
}
void pop(){
if (empty())
return;
swap(c.front(), c.back()); //vector不提供头删
c.pop_back();
DownwardMove(0); //头结点,向下调整-该结点与子结点比较调整
}
size_t size() const{
return c.size();
}
bool empty() const{
return c.empty();
}
const T& top() const{ //堆顶元素不允许修改,否则会破坏堆的特性
return c.front();
}
private:
//向上调整
void UpwardMove(int childdex){
int parentdex = ((childdex - 1) >> 1); //该结点的双亲结点的下标
while (childdex){
if (com(c[parentdex], c[childdex])){
swap(c[parentdex], c[childdex]);
childdex = parentdex;
parentdex = ((childdex - 1) >> 1);
}
else
return;
}
}
//向下调整
void DownwardMove(int parentdex){
size_t childdex = 2 * parentdex + 1;
while (childdex < c.size()){
//找到以parentdex为双亲结点的较大的孩子结点
if (childdex + 1 < c.size() && com(c[childdex], c[childdex + 1]))
childdex += 1;
//检测双亲是否满足大堆性质
if (com(c[parentdex], c[childdex])){
swap(c[parentdex], c[childdex]);
parentdex = childdex;
childdex = parentdex * 2 + 1;
}
else
return;
}
}
private:
Container c; //底层容器
Compare com; //元素大小比较标准
};
}