✍作者:阿润菜菜
专栏:C++
优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的(默认大堆)。优先级队列的内部实现通常是用堆来维护元素的优先级,使得每次出队的元素都是当前队列中优先级最高的元素。
优先级队列与普通队列的区别和优势有以下几点:
底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭
代器访问,并支持以下操作:
empty():检测容器是否为空
优先级队列的常用操作和方法有以下几种:
优先级队列的内部实现原理是利用一种特殊的数据结构,叫做堆。堆是一种完全二叉树,它的每个节点都小于(或大于)它的所有后代,这样就可以保证根节点是最小(或最大)的元素。
优先级队列可以用数组来存储堆的结构,数组中第一个元素是根节点,然后按照层次顺序依次存储其他节点。数组中下标为k的元素的父节点的下标为k/2,其子节点的下标为2k和2k+1。
优先级队列的插入和删除操作都需要维护堆的有序性。插入操作是将元素追加到数组的尾部,然后执行上浮操作,即递归地将元素与其父节点比较并交换,直到找到合适的位置或者到达根节点。删除操作是将数组中第一个元素(即最小或最大元素)移除,并将数组中最后一个元素移到第一个位置,然后执行下沉操作,即递归地将元素与其子节点比较并交换,直到找到合适的位置或者到达叶子节点。
#pragma once
#include
using namespace std;
#include
// priority_queue--->堆
namespace HUE
{
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 = std::vector<T>, class Compare = less<T>>
class priority_queue
{
public:
// 创造空的优先级队列
priority_queue() : c() {}
template<class Iterator>
priority_queue(Iterator first, Iterator last)
: c(first, last)
{
// 将c中的元素调整成堆的结构
int count = c.size();
int root = ((count - 2) >> 1);
for (; root >= 0; root--)
AdjustDown(root);
}
void push(const T& data)
{
c.push_back(data);
AdjustUP(c.size() - 1);
}
void pop()
{
if (empty())
return;
swap(c.front(), c.back());
c.pop_back();
AdjustDown(0);
}
size_t size()const
{
return c.size();
}
bool empty()const
{
return c.empty();
}
// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
const T& top()const
{
return c.front();
}
private:
// 向上调整
void AdjustUP(int child)
{
int parent = ((child - 1) >> 1);
while (child)
{
if (Compare()(c[parent], c[child]))
{
swap(c[child], c[parent]);
child = parent;
parent = ((child - 1) >> 1);
}
else
{
return;
}
}
}
// 向下调整
void AdjustDown(int parent)
{
size_t child = parent * 2 + 1;
while (child < c.size())
{
// 找以parent为根的较大的孩子
if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))
child += 1;
// 检测双亲是否满足情况
if (Compare()(c[parent], c[child]))
{
swap(c[child], c[parent]);
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
private:
Container c;
};
}
void TestQueuePriority()
{
HUE::priority_queue<int> q1;
q1.push(5);
q1.push(1);
q1.push(4);
q1.push(2);
q1.push(3);
q1.push(6);
cout << q1.top() << endl;
q1.pop();
q1.pop();
cout << q1.top() << endl;
vector<int> v{ 5,1,4,2,3,6 };
HUE::priority_queue<int, vector<int>, HUE::greater<int>> q2(v.begin(), v.end());
cout << q2.top() << endl;
q2.pop();
q2.pop();
cout << q2.top() << endl;
}
优先级队列的优缺点和改进方向有以下几种:
参考:Priority Queue