基于最大堆实现最大优先队列

问题描述:      

优先队列(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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值