一,最大优先级队列基本概念
最大优先队列不是一种普通的先进先出队列(和队列一样),它维护的元素有个优先级属性,不管如何进队列,出列队的都是优先级最大的元素!通常应用在计算机的分时调度,最小生成树的Prim算法等。
在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。优先级队列中有多个事件发生,每个事件有自己独立的优先级,优先级是非负数,数值越大优先级越高。采用最大优先级队列模拟事件执行的优先顺序。
1,最大优先级队列的操作
(1)HEAP_MAXIMUM
用O(1)时间实现MAXIMUM(S)操作,即返回最大堆第一个元素的值即可(return A[1])。
(2)HEAP_EXTRACT_MAX
实现EXTRACT_MAX操作,删除最大堆中第一个元素,然后调整堆。操作过程如下:将最堆中最后一个元素复制到第一个位置,删除最后一个节点(将堆的大小减少1),然后从第一个节点位置开始调整堆,使得称为新的最大堆。伪代码如下:
(3)HEAP_INCREASE_KEY
实现INCREASE_KEY,通过下标来标识要增加的元素的优先级key,增加元素后需要调整堆,从该节点的父节点开始自顶向上调整。
(4)MAX_HEAP_INSERT
实现INSERT操作,向最大堆中插入新的关键字。新的关键字插入在优先级的队尾部,然后从尾部的父节点开始自顶向上调整堆.
二,最大优先级队列C++实现
注:本代码基于最大堆
1,Heap.h实现
#include "stdafx.h"
#include "iostream"
#include "vector"
using namespace std;
template <typename DataType>
class Heap
{
public:
Heap(int size)
{
heapSize=size;
nLen=0;
a=new DataType[size];
if (a==NULL)
{
exit(1);
}
}
~Heap()
{
if (a!=NULL)
{
delete a;
a=NULL;
}
}
int Left(int i)
{
return 2*i+1;
}
int Right(int i)
{
return 2*i+2;
}
int Parent(int i)
{
return i/2;
}
void swap(DataType *a,DataType *b)
{
DataType temp;
temp=*a;
*a=*b;
*b=temp;
}
void KeepMaxHeap(int i,int heapsize);
void BuildMaxHeap();
void HeapSort();
void InitArr();
void printArray();
void HeapIncreaseKey(int i,DataType key);
DataType HeapMax();
DataType HeapExtractMax();
private:
int heapSize;
int nLen;
DataType *a;
};
template <typename DataType>
void Heap<DataType>::InitArr()
{
for (int i=0;i < heapSize;i++)
{
int key=rand()%10;
a[i]=key;
nLen++;
}
}
//打印数组
template <typename DataType>
void Heap<DataType>::printArray()
{
cout<<"当前数组结果为: ";
for ( int i = 0; i < nLen; i++ )
{
cout << a[ i ]<<" ";
if ((i+1)%10 == 0)
{
cout<<endl;
}
}
cout<<endl;
}
//保持堆的性质
//使a[i]这个元素下降(如果不满足最大根要求的话)
template <typename DataType>
void Heap<DataType>::KeepMaxHeap( int i,int hpsize)
{
int l=Left(i);
int r=Right(i);
int largest=0;
if (l<= hpsize && a[l]>a[i])//与左子比
{
largest=l;
}
else
{
largest=i;
}
if (r <= hpsize && a[r]> a[largest])//将较大者与右子比
{
largest=r;
}
if (largest!=i)
{
swap(&a[i],&a[largest]);
KeepMaxHeap(largest,hpsize);
}
}
//创建堆,将数组调整为最大堆
template <typename DataType>
void Heap<DataType>::BuildMaxHeap()
{
heapSize=nLen-1;
for (int i=heapSize/2 ; i>=0 ;i-- )
{
//heapsize/2+1到a.size-1的整数都是树叶,所以只需对0到heapsize/2作处理
KeepMaxHeap(i,heapSize);
}
}
//堆排序
template <typename DataType>
void Heap<DataType>::HeapSort()
{
BuildMaxHeap();//使数组成为最大堆
heapSize=nLen-1;
for (int i=heapSize;i>0;i--)
{
swap(&a[0],&a[i]);
heapSize--;
KeepMaxHeap(0,heapSize);//保持堆的性质
}
}
template <typename DataType>
DataType Heap<DataType>::HeapMax()
{
return this->a[0];
}
template <typename DataType>
DataType Heap<DataType>::HeapExtractMax()
{
if (0 >= nLen )
{
cerr<<"Heap UnderFlow"<<endl;
}
DataType max=a[0];
a[0]=a[heapSize];
heapSize--;
KeepMaxHeap(0,heapSize);
return max;
}
template <typename DataType>
void Heap<DataType>:: HeapIncreaseKey(int i,DataType key)
{
if (key < a[i])
{
cerr<<"新的值key比原值更小"<<endl;
}
a[i]=key;
while (i>1&&a[Parent(i)]<a[i])
{
swap(&a[i],&a[Parent(i)]);
i=Parent(i);
}
}
2,主测试程序
// ConsoleAppPriorityQueue.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "Heap.h"
#include "iostream"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
system("color 0A");
Heap<int> hp(10);
hp.InitArr();
hp.printArray();
//hp.HeapSort();
//hp.printArray();
hp.BuildMaxHeap();
int bb=hp.HeapExtractMax();
cout<<"去掉并获取当前堆中最大值:"<<bb<<endl;
int cc=hp.HeapExtractMax();
cout<<"去掉并获取当前堆中最大值:"<<cc<<endl;
int cc1=hp.HeapExtractMax();
cout<<"去掉并获取当前堆中最大值:"<<cc1<<endl;
int cc2=hp.HeapExtractMax();
cout<<"去掉并获取当前堆中最大值:"<<cc2<<endl;
int aa=hp.HeapMax();
cout<<"获取当前堆中最大值:"<<aa<<endl;
aa=hp.HeapMax();
cout<<"再次取当前堆最大值:"<<aa<<endl;
hp.HeapIncreaseKey(0,10);
aa=hp.HeapMax();
cout<<"获取当前堆位置为0,且被增加到10的元素:"<<aa<<endl;
system("pause");
return 0;
}
3,测试结果