1、什么是优先级队列?
顾名思义就是带有优先级的队列,既然是队列,就只能再一端插入,在另一端提取元素,优先级体现在,随便插入元素,他
会自动按照大或者这小的顺序进行排序。
2、用什么结构来实现它呢?如果我们用普通的数组,那么入队时很简单直接随便放入数组,只需要O(1)的时间,然而在出队时要挑选最大的那个优先级,则需要O(n)的时间。同样如果是有序的数组,入队时需要维护这个数组的有序性,找到此优先级合适的位置,需要O(n) 的时间,出队就很简单只需要拿出数组第一个就好了。而如果使用堆的话,则可以非常好的平衡入队与出队的时间复杂度。 使用堆可以将入队与出队的时间复杂度都变成lg(n)级别,虽然使用堆在入队上是慢于普通数组,在出队上是慢于有序数组的,可是平均来讲,使用堆来实现优先队列的时间复杂度大大低于我们使用数组来实现。
//仿函数(函数对象)重载operator()
template <class T>
class Less {
public:
bool operator()(const T& l, const T& r) {
return l < r;
}
};
template<class T>
class Greater {
public:
bool operator()(const T& l, const T& r) {
return l > r;
}
};
template <class T, class Contain = vector<T>, class Compare = Less<T> >
class PriorityQueue {
public :
Compare com;
void AdjustUp(size_t child)
{
//计算父节点位置
size_t parent = (child - 1) / 2;
while (child > 0) {
//com.operator()(_con[child], _con[parent])
//仿函数里面其实就是重载了operator(),但要注意如果容器中放的是自定义
//类型的数据,必须重载operator> 和 operator <
//com其实就表示某种优先级,比如说我们现在要按降序进行排列那么下面的
//表达式就转化为 if(_con[child] > _con[parent])
if (com(_con[child] , _con[parent])) {
//交换这个节点和它的父节点
swap(_con[child], _con[parent]);
//继续上调
child = parent;
parent = (child - 1) / 2;
}
else
//满足堆性质,直接break
break;
}
}
void AdjustDown(size_t parent)
{
//计算左孩子的位置
size_t child = parent * 2 + 1;
while (child < _con.size()) {
//com和上面一样是某种优先级,假如还是降序输出,我们首先要找出左右孩子
//中较大的那一个,然后和parent进行比较(前提是右孩子存在)
if ((child + 1 < _con.size()) &&
com(_con[child + 1],_con[child])) {
++child;
}
//如果左右孩子中较大的那个孩子比parent大,交换,然后向下调整
if (com(_con[child],_con[parent])) {
swap(_con[parent], _con[child]);
parent = child;
child = parent * 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);
}
size_t Size()
{
return _con.size();
}
bool Empty()
{
return _con.empty();
}
//返回const是因为堆的元素不能随便修改,否则不满足性质
const T& Top()
{
return _con[0];
}
private:
Contain _con;
};
void TestPriorityQueue()
{
PriorityQueue<int, vector<int>, Greater<int>> p;
p.Push(4);
p.Push(9);
p.Push(32);
p.Push(67);
p.Push(54);
p.Push(5);
while (!p.Empty()) {
cout << p.Top() << " ";
p.Pop();
}
cout << endl;
}