以最小堆为例,实现下列操作:
//向下调整算法
void down(int p) {
int a = heap[p], q = 2*p;//p代表当前节点,p代表子节点
while(q <= heapNum) {
if (heap[q] > heap[q+1] && q < heapNum) //q<heapNum小心别少了
q++;
if (a <= heap[q]) break;
heap[p] = heap[q];
p = q;
q = 2*p;
}
heap[p] = a;//安排原来的节点,这种交换可以学学
}
//删除根节点
int DeleteMin() {
int r = heap[1];//取出最小元素
heap[1] = heap[heapNum--];//然后把最后一个叶子结点赋给根结点
down(1);//再向下调整
return r;
}
//向上调整算法
void up(int p) {
int q = p/2, a = heap[p];//p为当前结点,q为父母结点
while(q >= 1 && heap[q] > a) {
heap[p] = heap[q];
p = q;
q = p/2;
}
heap[p] = a;
}
//插入
void insert(int a) {
heap[++heapNum] = a;//先把a插入到最后一个元素
up(heapNum);//再向上调整
}
//将p的优先级上升为a
void IncreaseKey(int p, int a) {
if (heap[p] <= a) return;//如果当前结点小于a就退出
heap[p] = a;
up(p);
}
//建立堆
void Build() {
for(int i = heapNum/2; i > 0; i--)//从最后一个非终端结点开始进行调整
down(i);
}
例题:poj 2051Argus
思路:维持一个最小堆,每次输出根结点,然后再相应地改变根结点的时间,向下调整最小堆。如此执行k次。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1008;
int k, st;
int sh[3008]; //ID与周期的映射表
struct heap{
int Q_num, Period;
};
heap t[maxn]; //最小堆
void adjust(int j) { // 向下调整
int q = 2*j;
heap m = t[j];
while(q <= st) {
if ((t[q].Period > t[q+1].Period ||
(t[q].Period == t[q+1].Period && t[q].Q_num > t[q+1].Q_num)
)&& q < st) //先比较周期在比较ID
q++;
if (m.Period < t[q].Period ||
(m.Period == t[q].Period && m.Q_num < t[q].Q_num))
break;
//很多人会写t[q] = m;这个不用写因为上面if就是用m来判断的
t[j] = t[q];
j = q;
q = 2*j;
}
t[j] = m;
}
void input(){
string cc;
st = 0;
while(cin>>cc, cc != "#") {
st++;
scanf("%d%d", &t[st].Q_num, &t[st].Period);
sh[t[st].Q_num] = t[st].Period;
}
for(int i = st/2; i > 0; i--)//初始化最小堆,这里i一开始为什么等于st/2呢?
adjust(i);//因为总节点数为i的二叉树,除开叶子节点还有i/2个节点;
scanf("%d", &k);
}
int dele(){
int result = t[1].Q_num;
t[1].Period += sh[t[1].Q_num];//修改顶点后再调整
adjust(1);
return result;
}
int main() {
input();
for(int i = 0; i < k; i++)
printf("%d\n", dele());
return 0;
}
优先队列:
基本操作:
empty() 如果队列为空返回真
pop() 删除对顶元素
push() 加入一个元素
size() 返回优先队列中拥有的元素个数
top() 返回优先队列对顶元素
用法:
示例:将元素5,3,2,4,6依次push到优先队列中,print其输出。
1. 标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。
priority_queue<int> pq;
通过<操作符可知在整数中元素大的优先级高。
故示例1中输出结果为: 6 5 4 3 2
2. 数据越小,优先级越高
priority_queue<int, vector<int>, greater<int> >pq;
其中
第二个参数为容器类型。
第二个参数为比较函数。
故示例2中输出结果为:2 3 4 5 6
3. 自定义优先级,重载比较符号
重载默认的 < 符号
struct node
{
friend bool operator< (node n1, node n2)
{
return n1.priority < n2.priority;
}
int priority;
int value;
};
这时,需要为每个元素自定义一个优先级。
poj 2051代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
struct Regist {
friend bool operator< (Regist a, Regist b) {
if (a.now == b.now)
return a.Q_num > b.Q_num;
else return a.now > b.now;
}
int Q_num, Period, now;
};
priority_queue<Regist> minheap;
int main() {
string c;
int k;
Regist one;
while(cin>>c && c != "#") {
scanf("%d%d", &one.Q_num, &one.Period);
one.now = one.Period;
minheap.push(one);
}
scanf("%d", &k);
while(k--) {
one = minheap.top();
minheap.pop();
printf("%d\n", one.Q_num);
one.now += one.Period;
minheap.push(one);
}
return 0;
}
两种方法在复杂度上面没什么区别!