基於最大堆實現最大優先隊列

問題描述:      

優先隊列(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;
}

發佈了79 篇原創文章 · 獲贊 62 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章