一、priority_queue介绍
优先级队列只提供了 push() pop() top() 函数,本质是一个堆,所以只有堆顶的元素有意义。
本质也是容器适配器,用的是 vector,就像数据结构阶段实现的堆一样,但是由于模板的引入,在这里的优先级队列支持传入比较函数对象来实现不同情况的比较,从而使堆顶的 top 是符合要求的。
priority_queue 与 sort 的对比
两者都是通过传入比较函数对象来实现特定的比较,但是底层是不同的。
(1)priority_queue 是通过模板参数来接受收比较函数对象的,sort 函数是通过函数参数来接受比较函数对象的。
(2)所以一个是类模板传类型,一个是函数模板传对象。
二、部分代码展示
#pragma once
#include<vector>
using namespace std;
namespace bit
{template<class T>struct Less{bool operator(const T& x1, const T& x2){return x1 < x2;}};template<class T>struct Greater{bool operator(const T& x1, const T& x2){return x1 > x2;}};// 默认传递大堆,类模板传类型,函数模板传对象(要有())template<class T, class Container = vector<T>, class Cmp = Less<T>>class priority_queue{public:void adjustup(size_t child){Cmp cmp;// 0 1 2int parent = (child - 1) / 2;while (child > 0) {if (cmp(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}}void adjustdown(size_t parent){Cmp cmp;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && cmp(_con[child], _con[child + 1]))child++;if (cmp(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}elsebreak;}}void push(const T& x){_con.push_back();adjustup(_con.size() - 1);}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}bool empty(){return _con.size() == 0;}const T& top(){return _con[0];}size_t size(){return _con.size();}private:Container _con;};
}
三、细节
push 和 pop 其实就是在维护一个堆,真正实现功能的是向上向下调整函数。
我们这里也和库一样实现两个比较类 Less 和 Greater,分别对应的是大堆和小堆。
要实现向上向下调整函数就一定要知道如何比较父子节点,此时比较类就可以通过模板参数来影响比较,实现功能。