优先队列(堆)满足先进先出,而且每次出队的都是队列中最小的(也可以是最大的,看实现过程)。
堆是一棵完全二叉树,所以优先队列一般用二叉堆实现。
分析:
1.一棵完全二叉树,所以可以用一个数组表示而不需要用指针。但是用数组就要事先估计堆的大小,所以用一个Capacity表示最大值。
2.因为保持堆序性质,最小元就是在根上,删除后还得做一些调整来保持完全二叉树的结构(实际就是删除最后一个元素,然后把它插入到队列中)。
3.若当前节点下标为i,则i2和i2+1就是它的左右孩子,我们在data[0]处放了一个MIN_INT。
4.入队:首先size++,如果data[size]插入不破坏结构,结束。否则,不断用父亲的值赋给当前节点,直到合适的位置。时间复杂度O(logN)。
5.出队:首先根节点置空,记录size点(last)的值然后size–,last能放入当前空穴就结束,否则,不断用儿子中最小的值赋给当前节点。时间复杂度O(logN)。(注释: 入队和出队的调整是一个逆向对称的过程)
6.队首:直接返回根节点的值,为最小值,O(1)。
代码:
PriorityQueue.h
#ifndef PRIORITYQUEUE_H
#define PRIORITYQUEUE_H
template<class T>
class PriorityQueue
{
private:
int Capacity = 100; //队列容量
int size; //队列大小
T* data; //队列变量
public:
PriorityQueue();
~PriorityQueue();
int Size();
bool Full(); //判满
bool Empty(); //判空
void Push(T key); //入队
void Pop(); //出队
void Clear(); //清空
T Top(); //队首
};
template<class T>
PriorityQueue<T>::PriorityQueue()
{
data = (T*) malloc((Capacity + 1)*sizeof(T));
if(!data)
{
perror("Allocate dynamic memory");
return;
}
size = 0;
}
template<class T>
PriorityQueue<T>::~PriorityQueue()
{
while(!Empty())
{
Pop();
}
}
template<class T>
//判空
bool PriorityQueue<T>::Empty()
{
if(size > 0)
{
return false;
}
return true;
}
template<class T>
//清空
void PriorityQueue<T>::Clear()
{
while(!Empty())
{
Pop();
}
}
template<class T>
//判满
bool PriorityQueue<T>::Full()
{
if(size == Capacity)
{
return true;
}
return false;
}
template<class T>
//大小
int PriorityQueue<T>::Size()
{
return size;
}
template<class T>
//入队
void PriorityQueue<T>::Push(T key)
{
//空队则直接入队
if(Empty())
{
data[++size] = key;
return;
}
int i;
if(Full())
{
perror("Priority queue is full\n");
return;
}
for(i = ++size; data[i/2] > key; i /= 2)
{
data[i] = data[i/2];
}
data[i] = key;
}
template<class T>
//队首
T PriorityQueue<T>::Top()
{
if(Empty())
{
perror("Priority queue is full\n");
return data[0];
}
return data[1];
}
template<class T>
//出队, 取完队首元素后,才执行出队操作,即去除堆顶元素,将末尾元素防止堆顶,并做sink调整
void PriorityQueue<T>::Pop()
{
int i, child;
T min, last;
if(Empty())
{
perror("Empty queue\n");
return;
}
// min = data[1];
last = data[size--];
for(i = 1; i * 2 <= size; i = child)
{
child = i * 2;
if(child != size && data[child + 1] < data[child])
{
child++;
}
if(last > data[child])
{
data[i] = data[child];
} else
{
break;
}
}
data[i] = last;
}
#endif // PRIORITYQUEUE_H
银行有1个服务员,n名顾客,每位顾客有到达时间和服务时间。
先到的顾客先服务,求总服务时间。
输入n 和 n 行 输出服务时间
样例输入:
3
1 3
3 5
10 4
样例输出:14
PriorityQueue.cpp
#include <iostream>
#include <queue>
#include "priorityqueue.h"
using namespace std;
const int MAXN = 1000;
//事件
struct Event
{
int arrive; //到达时间
int service; //服务时间
Event(){};
Event(int a, int s)
{
arrive = a;
service = s;
}
} cus[MAXN];
int operator > (const Event& a, const Event& b)
{
return a.arrive > b.arrive;
}
int operator < (const Event& a, const Event& b)
{
return a.arrive < b.arrive;
}
int main()
{
Event minCustomer(INT_MIN, 0);
PriorityQueue<Event> request; //顾客
int n, time;
while (cin >> n)
{
for (int i = 0; i < n; ++i)
{
cin >> cus[i].arrive >> cus[i].service;
request.Push(cus[i]); //顾客入队
}
time = 0; //服务时间
while (!request.Empty())
{
Event current = request.Top();
request.Pop();
//计算最后的时间节点
time = max(current.arrive + current.service, time + current.service);
}
cout << "time costs = " << time << endl;
}
return 0;
}
运行结果: