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