您的位置:首页 > 其它

算法导论第六章优先队列(二)

2015-09-20 17:16 489 查看
优先队列可以说是堆的一个非常重要的应用,和堆对应,优先队列也分最小优先队列和最大优先队列。

优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个关键字(key),关键字赋予了一个元素的优先级,故名为优先队列。之所以用堆来实现优先队列,我想最大的原因是堆很容易对元素按关键字进行排序。

优先队列的应用:

最大优先队列:其中最为典型的就是“共享计算机系统的作业调度”,通过记录各个作业的优先级,来调度一个作业的执行、删除和插入等操作。

最小优先队列:可以被用于“基于事件驱动的模拟器”,队列中保存要模拟的事件,每个事件都有一个发生时间作为关键字。事件必须按发生的时间顺序进行模拟,因为某一事件的模拟结果可能会触发对其他事件的模拟。

优先队列的实现:

为了实现优先队列,需要实现这样的几个过程:

1)Insert(S, x):插入x到集合S中;

2)Maximum(S):返回S中具有最大关键字的元素;

3)Extract_Max(S):去掉并返回集合S中具有最大关键字的元素;

4)Increase_Key(S, x, key):将元素x的关键字增加到key。

我们暂且不用管这些奇怪的函数为什么要这么定义,因为这是前人的成功经验总结,肯定是在实际应用中这几个函数用得是最多的,总之,知道这样的四个函数就行了,等用到的时候就知道它们的好处了。

首先,基于堆,Maximum可以在O(1)的时间内完成,如:

int PriorityQueue::HeapMaximum()    //return the maximum key from priority queue;
{
return GetQueueElement(0);        //the first element is max;
}


其次,Extract_Max(S)和Maximum()的区别就在于,得到了之后还要删除,在不改变结构的情况下,最好的删除方法就是用最后一个元素来代替第一个元素,但是要注意,删除之后,有可能堆的性质就不能保证了,所以,这个时候调用Max_Heapify()调整一下。如下:

int PriorityQueue::HeapExtractMax()        //delete and return the maximum key from queue;
{
if (IsEmptyHeap())
throw "heap underflow";

int heap_size = GetHeapSize();
int maxNum = GetQueueElement(0);
SetQueueElement(0, GetQueueElement(heap_size-1)); //A[1] = A[heap_size]
SetHeapSizeMinus1();
MaxHeapify(0);    //Max_Heapify()
return maxNum;
}


对于Increase_Key(S, x, key),我们直接用Key替换X,但是替换之后堆的性质也可能改变了,可以知道的是,X后面的元素仍然满足堆的性质,因为Key>X,这时就之用维护X前面的元素,一层层往上调用Max_Heapify()即可,如:

void PriorityQueue::HeapIncreaseKey(int srcIndex, int dstKey)    //increasing the srcKey to dstKey
{
if (dstKey < GetQueueElement(srcIndex))
throw "new key is smaller than current key!";
SetQueueElement(srcIndex, dstKey); //x = key
while(srcIndex > 0 && GetQueueElement(getParent(srcIndex)) < GetQueueElement(srcIndex)) {
Swap(srcIndex, getParent(srcIndex));
srcIndex = getParent(srcIndex); //get parent
}
}


最后,Insert(S, x)操作,我们可以在最后增加一个-∞的元素,然后将其转换成将-∞增加到x,即转换成Increase_Key(S, -∞, x)。如:

void PriorityQueue::HeapInsert(int key)    //insert key to the priority queue;
{
AddQueueElement(INT_MIN);            //add the INT_MIN to the end of heapQueue;
int heap_size = GetHeapSize();
HeapIncreaseKey(heap_size-1, key);
}


除此之外,习题6.5-8要求在O(lgn)的时间内实现一个Delete(S, i)操作。很容易想到相当于对A[i]为根的堆进行Extract_Max()操作。如:

Heap-Delete(A, i)
A[i] = A[A.heap-size]
A.heap-size = A.heap-size - 1
Heapify(A, i)


以上所有的操作,除了Maximum()之外,其余所有的函数的时间复杂度皆为O(lgn),所以,这也是为什么用堆来实现优先队列一个非常重要的原因。下面给出一个非常简单的优先队列的实现(元素的值就是Key)。

//MinHeap_KMerge.cpp

#include <iostream>
#include <vector>

using namespace std;

#include "MinHeap.h"

//merge the k list to a heap;
template<class T>
MinHeap<T>::MinHeap(size_t kSize)
{
if (!m_minHeap)
delete []m_minHeap;
m_minHeap = new T[kSize+1];
m_heapSize = 0;
}

//adjust the min heap;
template<class T>
void MinHeap<T>::MinHeapify(size_t index)
{
//assert
size_t heap_size = GetHeapSize();

while (true) {
size_t left = LEFT(index);
size_t right = RIGHT(index);

size_t smallest;
if (left < heap_size && HeapCompare(left, index))
smallest = left;
else smallest = index;
if (right < heap_size && HeapCompare(right, smallest))
smallest = right;

if (smallest != index) {
Swap(index, smallest);
index = smallest;
}
else break;
}
}

//insert element
template<class T>
void MinHeap<T>::HeapInsert(const T &element)
{
m_minHeap[m_heapSize] = element;
m_heapSize += 1;

size_t index = m_heapSize-1;

while (index > 0 && HeapCompare(index, PARENT(index))) {
Swap(index, PARENT(index));
index = PARENT(index);
}
}

//return and delete the min element
template<class T>
T MinHeap<T>::HeapExtractMin()
{
if (IsEmptyHeap())
throw "Heap is Empty!";
T minElement = HeapMin();

int heap_size = GetHeapSize();
m_minHeap[0] = m_minHeap[heap_size-1];
m_heapSize -= 1;
MinHeapify(0);
return minElement;
}

//return min element;
template<class T>
T    MinHeap<T>::HeapMin()  const
{
return m_minHeap[0];
}

int main()
{
const size_t k = 3;
vector<int> vecList[k];
vector<int>::iterator iterList[k];
vector<int> vecSort;
vector<int>::iterator iterS;

vector<int>::iterator it;

MinHeap<vector<int>::iterator> minHeap(k);
//first list
vecList[0].push_back(12);
vecList[0].push_back(24);
vecList[0].push_back(52);
cout << "first list:" << endl;
for ( it = vecList[0].begin();it != vecList[0].end(); ++it)
cout << *it << "->";
cout << "NULL" << endl;

vecList[1].push_back(9);
vecList[1].push_back(32);

cout << "second list:" << endl;
for ( it = vecList[1].begin();it != vecList[1].end(); ++it)
cout << *it << "->";
cout << "NULL" << endl;

vecList[2].push_back(34);
vecList[2].push_back(42);
vecList[2].push_back(78);
cout << "third list:" << endl;
for ( it = vecList[2].begin();it != vecList[2].end(); ++it)
cout << *it << "->";
cout << "NULL" << endl;

iterList[0] = vecList[0].begin();
iterList[1] = vecList[1].begin();
iterList[2] = vecList[2].begin();

minHeap.HeapInsert(iterList[0]);
minHeap.HeapInsert(iterList[1]);
minHeap.HeapInsert(iterList[2]);

while(minHeap.GetHeapSize()) {
it = minHeap.HeapExtractMin();
vecSort.push_back(*it);
++it;
if (it != vecList[0].end() && it != vecList[1].end() && it != vecList[2].end()) { //!!!!Expression vector iterators incompatible
minHeap.HeapInsert(it);
}
}

cout << "merge:" << endl;
for (iterS = vecSort.begin(); iterS != vecSort.end(); ++ iterS)
cout << *iterS << "->";
cout << "NULL" << endl;

return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: