我们在之前讲过的《堆的基础知识》和《堆排序》之后,我们来讲讲最大堆和最小堆的具体应用优先队列!
我们来看看这样的场景,给定你一组数据,要你在这组数据里面找到最大的那个数据,你要怎么做?
你可能会说直接遍历一次就行啦,运行时间也就
以
那有没有一种比较快速的方法可以做到在最少的时间代价内从一个元素个数和元素大小都会改变的一堆数据中找到最大/最小的那个。那就得优先队列出马啦!
优先队列的基础是最大堆/最小堆,是用来维护一组元素构成的集合key
.
一个最大优先队列支持如下操作:
- MAXIMUM(pQueue):得到
pQueue
里面key
值最大的元素- EXTRACT-MAX(pQueue):得到
pQueue
里面key
值最大的元素,并将这个元素从优先队列里面删除- INSERT(pQueue , E):在
pQueue
里面插入一个新的元素E
- INCRESED-KEY(pQueue , POS , NEWKEY):将
pQueue
里面位置POS
的元素key
值设为NEWKEY
最大优先队列在实际的应用中有非常多的用处,比如在计算机系统里面的任务,每一个任务都有一个优先级,每一个时刻都有可能添加(INSERT)的任务,计算机应该在这些任务里面得到优先级最高(EXTRAXCT-MAX)的任务优先进行处理。
相应的,最小优先队列里面应该有以下操作:MINIMUM,INSERT,EXTRACt-MIN,DECREASE-KEY等操作,最小优先队列可以作为基于事件驱动的模拟器。队列中要保存模拟的事件,每一个事件都以事件发生时间作为关键字。每次提出(EXTRACT-MIN)队列里面的发生时间最早的,每一时刻都有新的时间插入到队列里面去(INSERT)。
下面实现了优先队列的四个操作!
注意array
是最大堆,对元素从1开始,0位置存放堆大小
MAXIMUM
- 得到优先队列里面的最大值
- @param array 输入的优先队列
- @return 堆里面的最大值
int maximum(int array[]) { if(array == NULL || array[0] == 0) { cerr<<"The prority queue is EMPTY"<<endl; return INT_MIN; } return array[1]; }
这个代码很简单,直接返回最大堆的堆顶元素
array[1]
就可以啦
EXTRACT-MAX
- 取出优先队列里面的最大值
- @param array 优先队列
- @return 最大值
int extractMax(int array[]) { if(array == NULL || array[0] == 0) { cout<<"The priority queue is EMPTY"<<endl; return INT_MIN; } int maxNum = array[1]; array[1] = array[array[0]]; array[0]--; maxHeapify(array , 1); return maxNum; }
我们用堆末尾的元素替换到堆顶,然后再将这个堆顶元素进行堆性质的维护,将这个堆顶元素沉降到合适的位置!最后返回最大值
INCREASE-KEY
- 增加一个优先队列里面元素的键值
- @param array 优先队列
- @param pos 位置
- @param newKeyValue 新的键值
void increseKey(int array[] , int pos , int newKeyValue) { if(array == NULL || pos > array[0] || newKeyValue < array[pos]) { cerr<<"increse new key value failed"<<endl; return; } array[pos] = newKeyValue; while(pos > 1) { int fatherPos = PARENT(pos); if(array[pos] > array[fatherPos]) { exchange(array , pos , fatherPos); pos = fatherPos; } else break; } return; }
这里代码有点长,但是做的事情很简单,某一个位置的
key
值变大了,那么他的子树还是满足性质的,只是我们不能保证这个改变的节点使得array[PARENT(i)]
>array[i]
,于是我们需要将这个节点元素和父节点比较,如果父节点比较大,那么不做任何操作,要是子节点比较大,那么子节点与父节点交换,将这个较大的元素向上移动,这样循环操作直到到了父节点更大的情况或者到了根节点!
INSERT
- 在优先队列一个插入一个元素
- @param array 优先队列
- @param element 将要插入的元素
void insert(int array[] , int element) { if(array == NULL) return; if(array[0] >= 19) { cerr<<"Thy priority queue is FULL"<<endl; return; } array[0]++; array[array[0]] = INT_MIN; increseKey(array , array[0], element); }
这里用到了
increseKey
这个函数,我们在堆末尾插入一个新的元素,赋值为INT_MIN
,然后将这个值赋值为element
上移到合适的位置!
下面是完整代码
All Code
/*************************************************
* @Filename: pQueue.cc
* @Author: qeesung
* @Email: qeesung@qq.com
* @DateTime: 2015-05-07 16:49:55
* @Version: 1.0
* @Description: 优先队列
**************************************************/
#include <iostream>
#include <climits>
using namespace std;
/**
* 优先队列的基本操作
*/
#define PARENT(i) ((i)>>1)
#define LEFTCHILD(i) ((i)<<1)
#define RIGHTCHILD(i) (((i)<<1)+1)
#define MAX_HEAP_ARRAY_SIZE 20
/**
* 交换数组的两个位置的元素
* @param array 目标数组
* @param pos1 位置1
* @param pos2 位置2
*/
void exchange(int array[] , int pos1 , int pos2)
{
int temp = array[pos1];
array[pos1] = array[pos2];
array[pos2] = temp;
}
/**
* 维护最大堆的性质
* @param array 输入的最大堆
* @param pos 维护的位置
*/
void maxHeapify(int array[] , int pos)
{
if( array == NULL | pos > array[0])
return;
int leftChild = LEFTCHILD(pos);
int rightChild = RIGHTCHILD(pos);
int maxPos = pos;
if(leftChild <= array[0] && array[leftChild] > array[maxPos])
maxPos = leftChild;
if(rightChild <= array[0] && array[rightChild] > array[maxPos])
maxPos = rightChild;
if(maxPos != pos)
{
exchange(array , maxPos , pos);
maxHeapify(array , maxPos);
}
}
/**
* 建堆
* @param array 将要建堆的数组
*/
void buildHeap(int array[])
{
if(array == NULL || array[0] == 0)
return ;
for(int k = array[0]/2 ; k >= 1 ; --k)
{
maxHeapify(array , k);
}
}
/**
* 下面是优先队列的基本操作
*/
void increseKey(int array[] , int pos , int newKeyValue);
/**
* 在优先队列一个插入一个元素
* @param array 优先队列
* @param element 将要插入的元素
*/
void insert(int array[] , int element)
{
if(array == NULL)
return;
if(array[0] >= 19)
{
cerr<<"Thy priority queue is FULL"<<endl;
return;
}
array[0]++;
array[array[0]] = INT_MIN;
increseKey(array , array[0], element);
}
/**
* 得到优先队列里面的最大值
* @param array 输入的优先队列
* @return 堆里面的最大值
*/
int maximum(int array[])
{
if(array == NULL || array[0] == 0)
{
cerr<<"The prority queue is EMPTY"<<endl;
return INT_MIN;
}
return array[1];
}
/**
* 取出优先队列里面的最大值
* @param array 优先队列
* @return 最大值
*/
int extractMax(int array[])
{
if(array == NULL || array[0] == 0)
{
cout<<"The priority queue is EMPTY"<<endl;
return INT_MIN;
}
int maxNum = array[1];
array[1] = array[array[0]];
array[0]--;
maxHeapify(array , 1);
return maxNum;
}
/**
* 增加一个优先队列里面元素的键值
* @param array 优先队列
* @param pos 位置
* @param newKeyValue 新的键值
*/
void increseKey(int array[] , int pos , int newKeyValue)
{
if(array == NULL || pos > array[0] || newKeyValue < array[pos])
{
cerr<<"increse new key value failed"<<endl;
return;
}
array[pos] = newKeyValue;
while(pos > 1)
{
int fatherPos = PARENT(pos);
if(array[pos] > array[fatherPos])
{
exchange(array , pos , fatherPos);
pos = fatherPos;
}
else
break;
}
return;
}
/**
* 打印优先队列
* @param array 优先队列
*/
void printQueue(int array[])
{
cout<<"heap size : "<<array[0]<<" ---->";
for (int i = 1; i <= array[0]; ++i)
{
cout<<array[i]<<"\t";
}
cout<<endl;
}
int main(int argc, char const *argv[])
{
int array[]={0,4,1,3,2,16,9,10,14,8,7,0,0,0,0,0,0,0,0,0};
array[0] = 10;
cout<<"before builld heap:"<<endl;
printQueue(array);
buildHeap(array);
cout<<"after build heap:"<<endl;
printQueue(array);
cout<<"the max number is:"<<maximum(array)<<endl;
cout<<"extract maximum is :"<<extractMax(array)<<endl;
cout<<"after extract maximum number:"<<endl;
printQueue(array);
cout<<"increse pos 4 to 11:"<<endl;
increseKey(array , 4, 11);
printQueue(array);
cout<<"insert a new element 13:"<<endl;
insert(array , 13);
printQueue(array);
return 0;
}
运行结果:
before builld heap:
heap size : 10 —->4 1 3 2 16 9 10 14 8 7
after build heap:
heap size : 10 —->16 14 10 8 7 9 3 2 4 1
the max number is:16
extract maximum is :16
after extract maximum number:
heap size : 9 —->14 8 10 4 7 9 3 2 1
increse pos 4 to 11:
heap size : 9 —->14 11 10 8 7 9 3 2 1
insert a new element 13:
heap size : 10 —->14 13 10 8 11 9 3 2 1 7
原文地址:http://blog.csdn.net/ii1245712564/article/details/45566159