优先队列:
按键的大小排列的一种数据结构, 用堆实现性能最好,插入和删除操作都可以保证在对数时间内完成, 其中两个重要的操作为:删除最大元素、 插入元素。
堆
堆是一个完全二叉树, 堆中的每一个父节点都比两个子节点大, 一般用数组存放。
若当前节点为k,则它的孩子节点为2k、2k+1, 父节点为 k/2(向下取整)。
堆的两个核心操作为下沉和上浮, pq为数组,代码如下
void sink(int k){
while(2*k <= N){ //当k有孩子节点时循环
int j = 2*k; //令j指向k的左孩子
//若k有右孩子且右孩子大于左孩子的值, j指向右孩子
if(j < N && pq[j] < pq[j+1]) j++;
if(pq[j] < [q[k]) break; //如果孩子节点小于父节点, 下沉操作完成
swap(pq[j], pq[k]);
k = j; //孩子节点成为下次循环的父节点, 继续循环。
}
}
void swim(int k){
//若当前节点不为根节点并且当前节点大于父节点就交换两个节点。
while(k > 1 && pq[k] > pq[k/2]){
swap(pq[k], pq[k/2];
k /= 2;
}
}
下沉操作可以实现堆的删除最大元素, 上浮操作可以实现堆的插入元素。
代码如下
删除最大元素的操作:把最大元素与最后一个元素交换位置, 然后对根节点进行下沉操作,使堆重新有序。
int delMax(){
int m = pq[1];
swap(pq[N--], pq[1]);
sink(1);
return m;
}
插入操作: 将插入的元素放在最后一个并对其进行上浮操作。
void insert(int v){
pq[++N] = v;
swim(N);
}
下面就可以实现优先队列了。
#include<iostream>
using namespace std;
template <class T>
class priority_queue{
T *pq;
int N = 0;
void swim(int k){
while(k > 1 && pq[k] > pq[k/2]) {swap(pq[k], pq[k/2]); k /= 2;}
}
void sink(int k){
while(2*k <= N){
int j = 2*k;
if(j < N && pq[j] < pq[j+1]) j++;
if(pq[j] < pq[k])break;
swap(pq[j], pq[k]);
k = j;
}
}
void swap(int &a, int &b){
T t = a;
a = b;
b = t;
}
public:
priority_queue(int n){pq = new T[N+1];}
void insert(T v){
pq[++N] = v;
swim(N);
}
T delMax(){
T m = pq[1];
swap(pq[N--], pq[1]);
sink(1);
return m;
}
T Max(){return pq[1];}
int size(){return N;}
bool empty(){return N == 0;}
};
int main(){
priority_queue<int> q(10);
q.insert(1);
q.insert(3);
q.insert(2);
cout << q.delMax();
return 0;
}