在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。优先级队列中有多个事件发生,每个事件有自己独立的优先级,优先级是非负数,数值越大优先级越高。采用最大优先级队列模拟事件执行的优先顺序。
(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操作,向最大堆中插入新的关键字。新的关键字插入在优先级的队尾部,然后从尾部的父节点开始自顶向上调整堆.
注:本代码基于最大堆
#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); } }
// 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; }
注:
本文部分文字学习并copy自网络,代码参考并改编自算法导论.
如果侵犯了您的版权,请联系本人[email protected],本人将及时编辑掉!
【1】《维基百科》
【2】《算法导论》
【3】http://www.cnblogs.com/Anker/archive/2013/01/23/2873951.html
【4】《STL源码剥析》侯捷著