使用大顶堆可以高效的实现优先级队列,具体大顶堆的用法,可参考:堆排序
优先级队列是用来维护一组元素构成的集合S 的数据结构,每一个元素都含有一个关键字key。一个最大优先级队列支持一下操作:
Insert(S,x):把元素x插入到队列中,与一般队列不同的是,优先级队列入队的操作总和队列中已有的元素进行比较,找到适当的位置进行插入,本例中,入队的操作总是能使优先级队列保持有序状态。
Maximum(S):返回S中具有最大关键字的元素
Extract_Max(S):去掉并返回S中具有最大关键字的元素,其实就是出队操作,在大顶堆中,由于最大元素总是在根节点处,所以出队时仅需要去掉根节点并重新建堆即可。
Increase_Key(S,x,k):将元素x的值增加到k,这里k的值不能小于x的值
以下是具体实现代码:
#include <stdio.h>
#include <stdlib.h>
#define INF -10000//为什么要设置为那么小?相当于把这个元素放在队尾,增加到key时一层一层向上,完成队列的入队操作
#define MAX 20
/*一下操作是大顶堆的基本操作*/
//堆的大小,注意,和数组本身的大小事有区别的,在堆排序的函数中要尤其小心
int Heap_Size=20;
//保持堆的性质,其实就是拿A[i]和左右两个孩子比较大小,然后递归下去就行了
void MAX_HEAPIFY(int* A,int i)
{
int Largest;
int L=2*i;
int R=2*i+1;
if(L<=Heap_Size&&A[L]>A[i])
Largest=L;
else
Largest=i;
if(R<=Heap_Size&&A[R]>A[Largest])
Largest=R;
if(Largest!=i)
{
int temp=A[i];
A[i]=A[Largest];
A[Largest]=temp;
MAX_HEAPIFY(A,Largest);
}
}
//建堆的过程
void Build_Max_Heap(int* A)
{
int i=MAX/2;
for(;i>=1;i--)
{
MAX_HEAPIFY(A,i);
}
}
//堆排序算法的过程
void Heap_Sort(int* A)
{
Build_Max_Heap(A);
int i=MAX;
for(;i>2;i--)
{
printf("%d ",A[1]);
int temp=A[1];
A[1]=A[i];
A[i]=temp;
Heap_Size--;
MAX_HEAPIFY(A,1);
}
}
/*以下代码是优先级队列的基本操作*/
//返回最大值
int Heap_Maximum(int* A)
{
return A[1];
}
//出队操作,也就是讲A[1]出队,并重新生成大顶堆
int Heap_Extract_Max(int* A)
{
if(Heap_Size<1)
exit(-1);
int max=A[1];
A[1]=A[Heap_Size];
Heap_Size--;
MAX_HEAPIFY(A,1);
return max;
}
//将其中一个元素的值增大到key后堆的变化,主要为后续的入队操作打下基础
void Heap_Incerase_Key(int* A,int i,int key)
{
if(key<A[i])
exit(-1);
A[i]=key;
while(i>1&&A[i/2]<A[i])
{
int temp=A[i/2];
A[i/2]=A[i];
A[i]=temp;
i=i/2;
}
}
//入队操作,在数组左后一个位置放上值为非常小的数,然后通过Heap_Incerase_Key重新构造堆的结构
void Max_Heap_Insert(int* A,int key)
{
Heap_Size++;
A[Heap_Size]=INF;
Heap_Incerase_Key(A,Heap_Size,key);
}
//主函数进行测试,注意,数组下标从1开始,第一个元素存放数组的大小
int main(void)
{
int A[MAX+1]={MAX,34,23,67,34,2,5,6,1,78,34,2,4,5,44,12,6,97,23,54,10};
Build_Max_Heap(A);
printf("出队的元素是%d\n",Heap_Extract_Max(A));
printf("出队的元素是%d\n",Heap_Extract_Max(A));
Max_Heap_Insert(A,100);
printf("出队的元素是%d\n",Heap_Extract_Max(A));
return 0;
}