一、优先级队列
1.1介绍
优先级队列(Priority Queue)是一种特殊的数据结构,其并不满足队列先进先出的原则,它结合了队列和堆的特点,允许我们在其中插入元素,并且能够保证任何时候提取出的元素都是当前队列中具有最高(或最低)优先级的元素。在优先级队列中,每个元素都有一个关联的优先级值,这个值通常用于决定元素在队列中的相对位置。
基本特性:
-
插入(Enqueue):可以向优先级队列中添加元素,新元素会被放置在正确的位置以保持队列的优先级特性。
-
删除(Dequeue/Peek):从优先级队列中删除或查看优先级最高的元素(如果是最大优先级队列)或最低的元素(如果是最小优先级队列)。这一操作也称为取队首元素,但在优先级队列中,队首元素并不总是最先入队的元素,而是优先级最高的元素。
-
排序性质:优先级队列内的元素始终按照优先级排序,这意味着即使新元素不断加入,队列仍然能快速提供最高(或最低)优先级的元素。
优先级队列是一种非常实用的数据结构,适用于那些需要高效处理动态优先级数据的场景,它可以灵活地满足按照优先级而非简单时间顺序处理数据的需求。
1.2 使用介绍
定义:
template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
解释:
- T为数据的类型
- Container为容器适配器的类型,缺省值为vector<T>,也可以显示传queue等用数组实现的容器
- Compare是用来控制大小堆的,缺省值为less<T>为大堆,也可以传greater<T>,less与greater都是仿函数
常用接口:
函数声明 | 接口说明 |
prioprity_queue() | 构造一个空的优先级队列 |
empty() | 检测优先级队列是否为空,是返回true,否则返回 false |
top() | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
代码示例:
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}
二、priority_queue模拟实现及仿函数讲解
1. 结构
template<class T,class Container=vector<T>,class Cmp=Less<T>>class priority_queue{private:Container _con;//容器Cmp _cmp;//仿函数对象};
2.仿函数
仿函数是指一类特殊的类,这类类通过在其内部重载operator()
运算符,使得该类的对象可以像普通函数一样被调用。当对仿函数对象进行“函数调用”时,实际上执行的是operator()
成员函数。在向上调整与向下调整时,需要一个方式来如何比较大小,也就是控制大小堆,这个功能可以使用函数指针来实现,但C++更偏向于使用仿函数
注意如果要将自定义类型放入priority_queue中的话,一定要在自定义类型中重载<或者>
3.push
将数据插入容器尾部,通过向上调整法调整到合适位置
void push(const T& x){_con.push_back(x);adjustUp(_con.size()-1);}//向上调整算法void adjustUp(size_t child){int parent = (child - 1) / 2;while (child > 0){//利用仿函数比较if (_cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}}
4.pop
交换交换堆顶与堆尾的元素,删除堆尾元素,并将堆头元素向下调整到合适位置
void adjustDown(size_t parent){size_t 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])){swap(_con[parent], _con[child]);parent = child;child = child * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustDown(0);}
5.empty
bool empty(){return _con.empty();}
6.size
const size_t size() const{return _con.size();}
7.top
const T& top() const{return _con[0];}
完整代码:
#include<vector>
using namespace std;
namespace zyq
{template<class T,class Container=vector<T>,class Cmp=Less<T>>class priority_queue{public:void adjustUp(size_t child){int parent = (child - 1) / 2;while (child > 0){if (_cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}}void adjustDown(size_t parent){size_t 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])){swap(_con[parent], _con[child]);parent = child;child = child * 2 + 1;}else{break;}}}void push(const T& x){_con.push_back(x);adjustUp(_con.size()-1);}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustDown(0);}bool empty(){return _con.empty();}const size_t size() const{return _con.size();}const T& top() const{return _con[0];}private:Container _con;Cmp _cmp;};template<class T>struct Less{bool operator()(const T& a, const T& b){return a < b;}};template<class T>struct Greater{bool operator()(const T& a, const T& b){return a > b;}};
}