堆的一个常见的应用:作为高效的优先队列。
优先队列是用来维护有一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字。一个最大优先队列支持一下操作:
INSERT(S,x): 将元素x插入集合中。
MAXIMUM(S):返回S中具有最大键字的元素。
EXTRACT-MAX(S):去掉并返回S中的具有最大键字的元素。
INCREASE-KEY(S,x,k):将元素x的关键字值增加到k,这里假设k的值不小于x原关键字值。
#include<iostream>
using namespace std;
void maxHeap(int *a,int i,int heapSize) //建立最大树堆
{
int l = 2*i;
int r = 2*i+1;
int largest=0;
if(l<=heapSize&&a[l-1]>a[i-1]) //左孩子大于父节点
largest = l;
else
largest = i;
if(r<=heapSize&&a[r-1]>a[largest-1]) //若右孩子比左孩子、父节点都大
largest = r;
if(largest!=i)
{
swap(a[i-1],a[largest-1]);
maxHeap(a,largest,heapSize); //检测孩子树
}
}
void buildMaxHeap(int *a,int heapSize) //建立堆
{
for(int i=heapSize/2;i>=1;--i) //从heapSize/2开始建堆
maxHeap(a,i,heapSize);
}
void heapSort(int *a,int heapSize) //堆排序
{
buildMaxHeap(a,heapSize); //建堆
for(int i=heapSize;i>=2;--i)
{
swap(a[0],a[i-1]);
--heapSize;
maxHeap(a,1,heapSize); //调整
}
}
void print(int *a,int num)
{
for(int i=0;i<num;++i)
cout<<a[i]<<ends;
}
void reallocate(int *a,int num,int key) //重新分配数组空间
{
a = (int *)realloc(a,num*sizeof(int));
a[num-1] = key;
}
//优先序列priority queue
int heapMaximum(int *a,int heapSize) //返回a中具有最大键字的元素
{
buildMaxHeap(a,heapSize); //建堆
return a[0];
}
int heapExtractMax(int *a,int heapSize) //去掉并返回a中的具有最大键字的元素
{
if(heapSize<1)
cerr<<"heap nuderflow";
buildMaxHeap(a,heapSize);
int max = a[0];
a[0] = a[heapSize-1];
--heapSize;
maxHeap(a,1,heapSize);
return max;
}
void heapIncreaseKey(int *a,int incNum,int key) //将元素incNum的关键字值增加到key,这里假设key的值不小于incNum原关键字值
{
if(a[incNum-1]>key)
cerr<<"new key is smaller than current key"<<endl;
a[incNum-1] = key;
while(incNum>1 && a[incNum/2-1]<a[incNum-1])
{
swap(a[incNum-1],a[incNum/2-1]);
incNum = incNum/2;
}
}
void maxHeapInsert(int *a,int heapSize,int key) //将元素key插入集合a中。
{
buildMaxHeap(a,heapSize);
++heapSize;
int minest = -65535;
reallocate(a,heapSize,minest);
heapIncreaseKey(a,heapSize,key);
}
int main()
{
int b[]={16,4,10,14,7,9,3,2,8,1};
int num = sizeof(b)/sizeof(b[0]);
int *a = (int*)malloc(num*sizeof(int));
for(int i=0;i<num;++i)
a[i] = b[i];
int inc;
cin>>inc;
maxHeapInsert(a,num,inc);
//print(a,num);
cout<<endl;
free(a);
return 0;
}
由于函数过多,调用起来很不方便,所以可以将堆排序和优先队列封装成类,且优先队列公有继承堆排序
#include<iostream>
using namespace std;
class Heap{
public:
void maxHeap(int *a,int i,int heapSize) //建立最大树堆
{
int l = 2*i;
int r = 2*i+1;
int largest=0;
if(l<=heapSize&&a[l-1]>a[i-1]) //左孩子大于父节点
largest = l;
else
largest = i;
if(r<=heapSize&&a[r-1]>a[largest-1]) //若右孩子比左孩子、父节点都大
largest = r;
if(largest!=i)
{
swap(a[i-1],a[largest-1]);
maxHeap(a,largest,heapSize); //检测孩子树
}
}
void buildMaxHeap(int *a,int heapSize) //建立堆
{
for(int i=heapSize/2;i>=1;--i) //从heapSize/2开始建堆
maxHeap(a,i,heapSize);
}
void heapSort(int *a,int heapSize) //堆排序
{
buildMaxHeap(a,heapSize); //建堆
for(int i=heapSize;i>=2;--i)
{
swap(a[0],a[i-1]);
--heapSize;
maxHeap(a,1,heapSize); //调整
}
}
};
void print(int *a,int num)
{
for(int i=0;i<num;++i)
cout<<a[i]<<ends;
}
void reallocate(int *a,int num,int key) //重新分配数组空间
{
a = (int *)realloc(a,num*sizeof(int));
a[num-1] = key;
}
//优先序列priority queue
class PriorityQueue:public Heap{ //继承堆类
public:
int heapMaximum(int *a,int heapSize) //返回a中具有最大键字的元素
{
buildMaxHeap(a,heapSize); //建堆
return a[0];
}
int heapExtractMax(int *a,int heapSize) //去掉并返回a中的具有最大键字的元素
{
if(heapSize<1)
cerr<<"heap nuderflow";
buildMaxHeap(a,heapSize);
int max = a[0];
a[0] = a[heapSize-1];
--heapSize;
maxHeap(a,1,heapSize);
return max;
}
void heapIncreaseKey(int *a,int incNum,int key) //将元素incNum的关键字值增加到key,这里假设key的值不小于incNum原关键字值
{
if(a[incNum-1]>key)
cerr<<"new key is smaller than current key"<<endl;
a[incNum-1] = key;
while(incNum>1 && a[incNum/2-1]<a[incNum-1])
{
swap(a[incNum-1],a[incNum/2-1]);
incNum = incNum/2;
}
}
void maxHeapInsert(int *a,int heapSize,int key) //将元素key插入集合a中。
{
buildMaxHeap(a,heapSize);
++heapSize;
int minest = -65535;
reallocate(a,heapSize,minest);
heapIncreaseKey(a,heapSize,key);
}
};
int main()
{
Heap heap;
PriorityQueue priQueue;
int b[]={16,4,10,14,7,9,3,2,8,1};
int num = sizeof(b)/sizeof(b[0]);
int *a = (int*)malloc(num*sizeof(int));
for(int i=0;i<num;++i)
a[i] = b[i];
// heap.heapSort(a,num);
// print(a,num);
int inc;
cin>>inc;
priQueue.maxHeapInsert(a,num,inc); //可以将heapSize调整为全局静态变量,
print(a,++num);
cout<<endl;
free(a);
return 0;
}
由于每个函数几乎都要调用heapSize,所以可以将heapSize调整为全局静态变量会更方便。