问题描述:
优先队列(Priority Queue)是一种用来维护一组元素构成的集合S的数据结构,其内每一个元素都有一个相关的值,称为关键字(key),一个最大优先队列有着以下操作:
Maxium(s):返回S中具有最大关键字的元素
Extract_Max(S):去掉并返回S中的具有最大关键字的元素
Increase_Key(S,x,k):将元素x的关键字增加到k,这里假设k不小于x的原关键字值。
Insert(S,x):把元素x插入集合S中
最大优先队列常用于共享计算机系统的作业调度,队列记录将要执行的各个作业以及它们之间的相对优先级,当一个作业完成或被中断后,调度器调用Extract_Max从所有等待作业中,选出具有最高优先级的作业来执行。在任何时候调度器可以调用Insert把一个新作业加入到队列中来。
分析:
假设数组下标从1开始,
Maxium:可以直接返回已建立最大堆数组的第一个元素Array[1]
Extract_Max:可以将最大元素提取后直接令Array[1] = Array[heapSize],然后让heapSize--,接着从根节点开始维护最大堆Max-Heapify(A,1)
Increase_Key:增加关键字值后需要找到合适的插入位置,变大了该节点关键字值后,不断的与它的父节点比较,如果它比父节点大,则与之互换。直到它的父节点比该节点关键值大结束。此时重新符合最大堆性质。
Insert:可以先增加一个节点关键值为-INF的叶节点,然后调用Increase_Key将关键值增加为指定关键字,同时heapSize++;
下面是代码:
#include<iostream>
#include<vector>
#include <time.h>
#include <stdlib.h>
using namespace std;
/*
用最大堆建立最大优先队列,队列中元素直接用键值来表示
队列有四个功能:插入元素x、返回最大关键值元素、
去掉并返回最大关键值元素、将元素x键值增加为k.
*/
class priorQueue{//队列元素中为作业对象
private:
vector<int> keyArray;//优先队列关键值,用于维护最大堆
void Max_Heapify(int i);//对下标为i的根节点子树维护最大堆性质
int getParentIndex(int i);//得到对节点i的父节点下标
public:
priorQueue(){}
~priorQueue(){}
int Maxium();//返回最大键值元素
int Extract_Max();//去掉并返回最大关键值元素
void Increase_Key(int i , int key);//增加队列中下标为i的元素键值为key
void Insert(int x);//插入作业
//---查看队列内部键值函数
void printQueue();
};
//---返回最大键值元素
int priorQueue::Maxium()
{
if(0 == keyArray.size()){
cout<<"队列为空!"<<endl;
return INT_MIN;//队列为空
}
return keyArray[0];
}
//对下标为i的非叶根节点子树维护最大堆性质
void priorQueue::Max_Heapify(int i)
{
//vector下标由0开始时左右孩子
if(keyArray.size() <= 1)//队列中只有小于一个作业时没有孩子节点,不需维护最大堆
return;
int left = 2*i+1;
int right = 2*i+2;
int nonLeaf = keyArray.size()/2-1;//非叶子节点下标
if(i <= nonLeaf){//i为非叶子节点才进行维护
//---寻找左右孩子中较大者与根节点i比较
int largest = i;//存储较大节点下标
if(keyArray[left] > keyArray[i])
largest = left;
if(right<keyArray.size() && keyArray[right]>keyArray[left])
largest = right;
if(largest != i){//如果最大值并非父节点,则互换二者
int temp = keyArray[i];
keyArray[i] = keyArray[largest];
keyArray[largest] = temp;
Max_Heapify(largest);
}
}
}
//---去掉并返回最大关键值元素
int priorQueue::Extract_Max()
{
if(0 == keyArray.size()){
cout<<"队列为空!"<<endl;
return INT_MIN;
}
int maxKey = keyArray[0];
//---依据关键值最大堆性质调整keyArray
keyArray[0] = keyArray[keyArray.size()-1];
keyArray[keyArray.size()-1] = maxKey;
keyArray.pop_back();//弹出最后一个元素
Max_Heapify(0);//重新从根节点开始维护
return maxKey;
}
int priorQueue::getParentIndex(int i)
{
if(i>=1)
return (i-1)/2;
return -1;
}
//增加队列中elem元素的键值为key
void priorQueue::Increase_Key(int i , int key)
{
if(i <= keyArray.size()-1 && i>=0){//有效下标
if(key < keyArray[i]){
cerr<<"指定欲增加的关键值比原有关键值小!"<<endl;
return;
}
keyArray[i] = key;
//新加入节点与父节点作比较,如果更大则调换二者位置
while(i>=1 && keyArray[getParentIndex(i)] < keyArray[i]){
int temp = keyArray[i];
keyArray[i] = keyArray[getParentIndex(i)];
keyArray[getParentIndex(i)] = temp;
i = getParentIndex(i);
}
}
}
//插入作业
void priorQueue::Insert(int x)
{
keyArray.push_back(INT_MIN);//设定新作业优先度为负无穷
Increase_Key(keyArray.size()-1 , x);//提升作业关键值
}
void priorQueue::printQueue()
{
for(vector<int>::iterator iter=keyArray.begin();iter!=keyArray.end();iter++)
cout<<*iter<<" ";
cout<<endl;
}
int main()
{
priorQueue q;
int task[9];
for(int i=0 ; i<9 ; i++){
task[i] = i+1;
q.Insert(task[i]);
}
cout<<q.Extract_Max()<<" "<<endl;
cout<<q.Extract_Max()<<" "<<endl;
q.Increase_Key(3,19);
cout<<q.Maxium()<<" "<<endl;
q.printQueue();
q.Insert(88);
cout<<q.Extract_Max()<<" "<<endl;
q.printQueue();
return 0;
}