优先队列/堆

来源:互联网 发布:php获取html内容 编辑:程序博客网 时间:2024/06/05 15:22

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]);elsebreak;//当父结点大于子结点,循环终止k = j;//向下沉}}


优先队列运用于在接近无限大N的输入中,找出最大(最小)的M个元素。

如果用数组来实现二叉堆的话,那么位置k的结点的父结点的位置为k/2,而它的两个子结点的位置分别为2k和2k+1

数组中A[0]不使用,示例代码中使用最大堆

优先队列能够保证插入元素和删除最大元素这两个操作复杂度为NlogM