template <typename T> class MaxQ {
public:
MaxQ(std::initializer_list<T> il) :_v(il) {}
size_t size() { return _v.size(); }
void showData() { for_each(_v.begin(), _v.end(),
[](const T x) {std::cout << x << " "; });
std::cout << std::endl; }
void insert(T value);
T delMax();
private:
void swim(int k);
void sink(int k);
std::vector<T> _v;
};
//往队列中末尾插入元素,并调用swim将其放在合适的位置
template <typename T>
void MaxQ<T>::insert(T value)
{
_v.push_back(value);
swim(_v.size() - 1);
}
template <typename T>
void MaxQ<T>::swim(int k)
{
//k代表的是在数组中的位置
//因为当k处于二叉堆的第2层,与第一层(即k=1)进行交换,所以这里的循环判断条件为 k > 1
//当父结点_v[k/2]小于当前处理的结点_v[k]时,k结点往上移
while (k > 1 && _v[k] > _v[k / 2]) {
std::swap(_v[k], _v[k / 2]);
k = k / 2; //跳至二叉堆的上一层
}
}
//弹出二叉堆中最大的元素,由insert已知最大值存在_v[1]
//将末尾元素提上来填补_v[1]的位置,接着将其下沉到合适的位置,因为堆在数组中的存储并不是有序的
template <typename T>
T MaxQ<T>::delMax()
{
assert(_v.size() >= 2);
auto max = _v[1];
std::swap(_v[1], _v[_v.size() - 1]);
_v.pop_back();
sink(1);
return max;
}
template <typename T>
void MaxQ<T>::sink(int k)
{
while (2 * k <= _v.size()-1 ) { //当下沉至>2k位置,表示已经在堆的底层,循环终止
int j = 2 * k;
if (j < _v.size()-1 && _v[j] < _v[j + 1]) //判断两个子结点的大小
++j;
if (_v[j] > _v[k]) //判断父结点k和子结点j的大小
std::swap(_v[j], _v[k]);
else
break; //当父结点大于子结点,循环终止
k = j; //向下沉
}
}
优先队列运用于在接近无限大N的输入中,找出最大(最小)的M个元素。
如果用数组来实现二叉堆的话,那么位置k的结点的父结点的位置为k/2,而它的两个子结点的位置分别为2k和2k+1
数组中A[0]不使用,示例代码中使用最大堆
优先队列能够保证插入元素和删除最大元素这两个操作复杂度为NlogM