优先级队列的实现
优先级队列,并不遵守先进先出的特性,所以可以说它并不是一个队列。尽管名字上有些想象。优先级队列,主要的特性就是,对存在里面的数据有了一个优先级高低的划分,或者大的优先级高,或者小的优先级高,出队时就根据优先级的高低进行出队。
跟据它的出入队特性,我们可以使用堆来对其进行构建。堆在物理结构上是一个连续的数组,可以支持下标的随机访问,而在逻辑上是一颗完全二叉树。通过构建大堆或者小堆完全满足它的按优先级最高的出队的要求,每次只需出堆顶的元素是即可。
pop
它的pop与其他的容器用法一样,只不过它出的是队列之中优先级较高的数据。
每次pop时要求出优先级最高的数据,这里先假定大的数优先级高。我们需要构建一个大堆,每次出堆顶的元素即可。
- 先将堆顶元素与最后一个元素交换位置
- 再将最后一个位置的元素pop掉
- 再重新向下调整成为堆
push
插入是个关键,我们需要插入每个元素后,都能保证它是一个堆,以便后面的操作
在最开始时,队列为空,所以我们只需要插入每一个后都维持其为大堆或者小堆。
- 先将元素尾插进底层容器
- 再将该元素进行向上调整成为堆
top
我们只需每次取出堆顶的元素即可,就是数组下标为0的元素。
实现代码:
#ifndef __PRIORITY_QUEUE_HPP__
#define __PRIORITY_QUEUE_HPP__
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
/*
*优先级队列: 根据出入的第三个模板参数,来确定是大的数为优先级高,还是小的优先级高
* pop时 每次pop出队列中最的或最小的数
* top时 top出最大或最小的数
* */
/* 通过构建堆来完成pop 与 top 的操作。
* vector 相当于一颗完全二叉树 ,可以通过下标随机访问,用来构建堆最合适
* */
/*
*使用仿函数来调整队列中的优先级
*/
template<class T>
class Less{ //大的优先级高,降序排列
public:
bool operator()(const T& a1, const T& a2)
{
return a1 > a2;
}
};
template<class T>
class Greater{ //小的优先级高,升序排列
public:
bool operator()(const T& a1,const T& a2)
{
return a1 < a2;
}
};
template<class T,class Container = std::deque<T> , class Compare = Less<T>>
class PriorityQueue{ //此时默认为less 大的数优先级高,只需在传入模板参数时进行选择即可
public:
void Push(const T& value)
{
_con.push_back(value); //插入到数组后最后一个位置
Adjustup(_con.size()-1); //再将数据向上调整重新构成堆
}
void Pop()
{
std::swap(_con[0],_con[_con.size()-1]); //使堆顶元素与最后一个元素交换位置,
_con.pop_back(); //再将最后一个元素删除
Adjustdown(); //再从堆顶开始将其调整为堆
}
T& top() //取出堆顶的元素
{
return _con[0];
}
void Adjustup(int n) //向上调整
{
Compare _com;
int child = n;
int parent = (child - 1 ) / 2;
while(child > 0) //当调整到堆顶元素时就停止
{
if(_com(_con[child] , _con[parent]))
std::swap(_con[parent],_con[child]);
child = parent;
parent = (child - 1 ) / 2 ;
}
}
void Adjustdown() //向下调整
{
Compare _com;
int parent = 0;
int child = parent * 2 + 1;
while(child < _con.size())
{
if(child +1 < _con.size() && _com(_con[child + 1] , _con[child]))
child = child + 1; //选两个孩子中较大的一个
if(_com(_con[child] , _con[parent])) //和双亲节点比较
std::swap(_con[child] , _con[parent]);
else break;
parent = child;
child = parent * 2 + 1;
}
}
size_t Size()
{
return _con.size();
}
bool Empty()
{
return _con.empty();
}
private:
Container _con;
};
# endif