优先级队列:priority_queue
template <class T,class Container=vector<T>,class Compare = less<T>>
class priority_queue
{
public:
private:
Container _con;
Compare com;
};
}
我们先来介绍一下priority_queue的类模板的第三个模板参数
class Compare = less<T>
这里的Compare我们给这个类模板参数一个缺省值
这个缺省值为仿函数
template<class T>
struct less
{
bool operator()(const T& l, const T& r)
{
return l < r;
}
};
template<class T>
struct greater
{
bool operator()(const T& l, const T& r)
{
return l > r;
}
};
仿函数的本质:就是重载operator(),并给两个参数,使这个类能像函数一样去使用。
我们先一口气把几个简单的函数直接给出
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
const T& top() const
{
return _con[0];
}
优先级队列:底层采用大小堆的方式(物理结构是vector),对push的数据进行大小排序
所以在push数据的时候,如果我们采用less这个类模板类型,则采用大堆存储,也就是当从头结点出数据的时候,会是一个降序的。传入greater的时候就恰恰相反。
void AdjustUp(size_t child)
{
size_t parent = (child - 1) / 2;
while (child>0)
{
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
我们将节点插入队尾,并进行向上调整,使之成为一个大堆(less)或者小堆(greater),这里的仿函数就是用来控制大小判断的。
void AdjustDown(size_t parent)
{
size_t child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child++;
}
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
删除数据时,先将队头的数据和最后一个数据交换,然后进行vector的pop_back(),就可以删除数据了。其中交换后,除了堆顶以外,它的孩子会形成两个大堆(小堆),我们对其进行向下调整,就会等到完整的大小堆。
我们进行测试:
int main()
{
www::priority_queue<int> pq;
pq.push(1);
pq.push(2);
pq.push(3);
pq.push(4);
pq.push(5);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
return 0;
}