码迷,mamicode.com
首页 > 其他好文 > 详细

优先队列

时间:2015-05-07 22:12:26      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:优先队列   最大堆   最小堆   

优先队列

我们在之前讲过的《堆的基础知识》《堆排序》之后,我们来讲讲最大堆和最小堆的具体应用优先队列

优先队列基础知识

我们来看看这样的场景,给定你一组数据,要你在这组数据里面找到最大的那个数据,你要怎么做?

  1. 你可能会说直接遍历一次就行啦,运行时间也就O(n),但是如果要求你在这堆数据里面找到最大的,然后删除,再在剩下的元素里面找到最大的,那还是要遍历一般所有数据。那有没有其他快速的方法呢?

  2. O(nlogn)将这些数据排序,想要第几大的直接取出来就可以啦,那如果要是向这堆数据里面插入一个新的数据怎么办?这时你可能要遍历性这些有序的数据,插入到合适的位置,这样不就行啦。不错,可是这样一次插入操作时间代价为O(n),这样也太慢了。要是你随意改变这堆数据里面的一个元素的话,那就要把这个改变的元素移动到合适的位置保证这堆数据还是有序的,特别是将这堆数据放在一个数组里面,插入一个新的元素会涉及到数组元素的移动。。。可以慢到抓狂了。

那有没有一种比较快速的方法可以做到在最少的时间代价内从一个元素个数和元素大小都会改变的一堆数据中找到最大/最小的那个。那就得优先队列出马啦!

优先队列的基础是最大堆/最小堆,是用来维护一组元素构成的集合S的数据结构,每一个元素都有一个相关的值,称之为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)。

优先队列C++实现

下面实现了优先队列的四个操作!
注意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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!