优先队列的操作
1.优先队列的定义
优先队列是一个以集合为基础的抽象数据类型。
优先队列中的每一个元素都有一个优先级。
定义在优先队列上的基本运算如下。
\(Min(H)\): 返回优先队列H中具有最下优先级的元素。
\(Insert(x,H)\): 将元素x插入优先队列H。
\(DeleteMin(H)\): 删除并返回优先队列H中具有最小优先级的元素。
在优先队列中,是按照每个对象的优先级顺序进行的。
2.优先队列的简单实现
所有实现字典的方法都可用于实现优先队列。优先队列中元素的优先级可以看成字典中元素的线性序值。
用有序链表实现优先队列,在O(1)时间内实现\(Min(H)\)和\(DeleteMin(H)\)运算,但\(Insert(x,H)\)运算在最坏情况下需要\(O(n)\)时间。\(n\)为插入元素时优先队列中已有的元素个数。
用二叉搜索树表示有\(n\)个元素的优先队列,在最坏情况下\(Insert(x,H)\)和\(DeleteMin(H)\)运算需要\(O(n)\)时间,在平均情况下需要\(O(logn)\)时间。
用无序链表实现优先队列,在\(O(1)\)时间内实现\(Insert(x,H)\)运算,但\(DeleteMin(H)\)运算却需要\(O(n)\)时间。
事实上,链表在用于存储普通队列时往往更为方便。
综上,一般使用二叉搜索树实现优先队列是总的时间复杂度更低的方法。
3.优先级树和堆
3.1优先级树
对二叉搜索树进行适当修改,将二叉搜索性质换成下面的优先性质,从而引入优先级树。
优先级树的性质:
\((1)\)树中每一结点存储一个元素。
\((2)\)任一结点中存储的元素的优先级不大于其儿子结点中存储的元素的优先级。(优先级越小越往树根走)
较高层结点有较小优先级,这类优先级树称为极小化优先级树。
若在一棵优先级树中,任一结点中存储的元素的优先级不小于其儿子结点中存储的元素的优先级,则相应的优先级称为极大化优先级树。
3.2堆
当一棵优先级树是近似满二叉树,称其为堆或偏序树。
极小化优先级树相应的堆称为极小化堆;极大化优先级树相应的堆称为极大化堆。
下图的优先级树是一个极小化堆。

通常情况下,堆即指极小化堆;优先级树即指极小化优先级树。
3.2.1堆的\(Delete(H)\)运算
4.用数组实现堆
6.优先队列的使用
6.1int型优先队列
应当注意,只有c++中才有封装好的 priority_queue ,也就是说,必须要在扩展名为 .cpp 的文件中直接用它才不会报错。
而它必要的头文件有:
点击查看代码
#include<queue>
#include<vector>
并且作为c++中的代码要用这些头文件需要加上这样一行:
using namespace std;
6.2结构体优先队列
结构体优先队列其实与int型优先队列比较类似,但由于结构体无法直接比较优先级,一般情况下我们需要对结构体进行重载优先级。
例如下面这个结构体,
点击查看代码
struct student {
char name[20];
int id;
int sum;
};
我们可以考虑直接在结构体内对它进行重载,就像这样:
struct student {
char name[20];
int id;
int sum;
bool operator < (const student& other) const {
return sum < other.sum;
}
};
priority_queue<student,vector<student>,less<student> > q;
需要注意的是,这里是大根堆的重载方式,如果是小根堆的话,应当这样重载:
点击查看代码
struct student {
char name[20];
int id;
int sum;
bool operator > (const student& other) const {
return sum > other.sum;
}
};
priority_queue<student,vector<student>,greater<student> > q;
在这里面, operator 后面的表示需要重载的是大于符号和小于符号,而在针对sum小根堆里面,优先级高的是sum小的,也就是作比较的时候小的sum优先级更高。
同时,还有另外一种重载优先级的办法。
你可以通过重新定义一个cmp来定义它们的优先级。
点击查看代码
struct student {
char name[20];
int id;
int sum;
};
struct cmp {
bool operator() (student x,student y) {
return x.sum<y.sum;
}
};
priority_queue<student,vector<student>,cmp > q;
这里是大根堆的一种定义形式,如果需要的是关于sum的小根堆,则只需要考虑把这里的大于符号换成小于符号即可。
你可以认为x和y是一段长度为2的序列,其中x在y的前面。只需要 x.sum < y.sum 那么返回值为真,它们就会发生顺序交换。

浙公网安备 33010602011771号