优先级队列其实就是一个堆,在cpp库里面默认为一个大根堆,它和双端队列一样,是一个容器适配器,默认用vector作为容器,类似数组。另外为了灵活的变换生成大根堆还是小根堆,可以用cpp的库(#include<functional>)里的仿函数来控制。
初学的时候对什么时候用向上调整好,什么时候用向下调整好把握不准,以大根堆为例,我个人认为在用迭代器初始化和进行删除的时候用向下调整好,插入的时候用向上调整好。删除的时候,是top的值与尾部互换后,再把尾部pop_back掉,需要调整的元素在顶部,所以只能用向下调整,而插入的时候是把元素插在尾部(vector),此时需要调整的元素在尾部,所以只能使用向上调整法。
而用迭代器初始化的时候,用向上调整和向下调整都可以达到目的,但是一看发现,使用向上调整时调用的函数次数会比向下调整建堆调用的函数次数要多,也就是资源的浪费,所以初始化的时候建议用向下调整建堆。
关系仿函数的补充
仿函数其实是一个类,它的里面会重写一个(),然后写一个的功能函数(一般多为比较大小等简单的函数)放在重写的()函数内,然后在类外实例化后就可以像函数一样使用,所以称为 仿函数 ,比如在模拟实现优先级队列中,它就是默认使用一个less仿函数(功能就是<)作为比较器,stl中默认使用的是greater作为比较器,这样使用者就可以通过显示传比较器来选择大根堆还是小根堆。
使用库里面的堆需要包头文件(<queue>),别忘了它是容器适配器,第二个模板参数可以决定它是用链表还是集合来作为它的数据结构。
cpp的优先级队列简单模拟实现及测试
#pragma once
#include<iostream>
#include<vector>
#include<functional>
namespace hzj
{
using namespace std;
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
private:
void AdjustUp(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (_com(_c[parent],_c[child]))
{
std::swap(_c[parent], _c[child]);
child = parent;
parent = (child - 1) / 2;
}
else break;
}
}
void AdjustDown(int parent)
{
int child = parent * 2 + 1;
int len = size();
while (child < len)
{
if (child + 1 < len && _com(_c[child] , _c[child + 1])) child++;
if (_com(_c[parent],_c[child]))
{
std::swap(_c[child], _c[parent]);
parent = child;
child = child * 2 + 1;
}
else break;
}
}
public:
priority_queue()
{}
template<class inputiterator>
priority_queue(inputiterator first, inputiterator last)
{
inputiterator it = first;
while (it != last)
{
_c.push_back(*it);
++it;
}
for (int i = (size() - 2) / 2; i >= 0;i--)
{
AdjustDown(i);
}
}
bool empty()const
{
return _c.empty();
}
size_t size()const
{
return _c.size();
}
const T& top()
{
return _c[0];
}
void push(const T& x = new T())
{
_c.push_back(x);
AdjustUp(size() - 1);
}
void pop()
{
std::swap(_c[0], _c[size() - 1]);
_c.pop_back();
AdjustDown(0);
}
private:
Container _c;
Compare _com;
};
void test1()
{
priority_queue<int> pq;
pq.push(1);
pq.push(2);
pq.push(3);
pq.push(4);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
void test2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
priority_queue<int> pq(v.begin(), v.end());
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
}