优先级队列是基于最大堆或者最小堆的,有很多的应用,比如任务调度,事件模拟之类的,下面我们来实现最大优先级队列(基于最大堆)和最小优先级队列(基于最小堆)。
最大优先级队列代码如下。在实际使用中,一般可以只保存一个用于比较的key和一个指向实际数据的指针在优先级队列中,下面的代码忽略了实际的数据,只考虑Key。
#ifndef _LARGESTPRIORITYQUEUE_
#define _LARGESTPRIORITYQUEUE_
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T, int MaxCount=100>
class LargestPriorityQueue
{
public:
LargestPriorityQueue(): _size(0)
{
_values = new T[MaxCount];
}
~LargestPriorityQueue() { delete [] _values; }
LargestPriorityQueue(const LargestPriorityQueue& rhs): _size(0),_values(NULL) { operator=(rhs); }
const LargestPriorityQueue& operator= ( const LargestPriorityQueue& rhs)
{
if( this != &rhs )
{
delete [] _values;
_values = new T[MaxCount];
_size = rhs._size;
for(int i=0;i<_size;++i)
_values[i] = rhs._values[i];
}
return *this;
}
bool IsEmpty() const { return _size == 0; }
bool Size() const { return _size; }
bool IsFull() const { return _size == MaxCount; }
void Insert(const T& value)
{
if(IsFull())
throw logic_error("Queue is full");
_values[_size++] = value;
int index = _size - 1;
int parent = (index - 1) / 2;
while( index > 0 && _values[parent] < _values[index] )
{
Swap(parent,index);
index = parent;
parent = (index - 1) / 2;
}
}
T GetLargest()
{
if(IsEmpty())
throw logic_error("No element in queue");
return _values[0];
}
T RemoveLargest()
{
if(IsEmpty())
throw logic_error("No element in queue");
T value = _values[0];
Swap(0,_size-1);
--_size;
MaxHeapify(0,_size-1);
return value;
}
void IncreaseKey(int index, const T& newValue)
{
if( index < 0 || index >= _size )
throw logic_error("Invalid element index");
if(_values[index] > newValue )
throw logic_error("New value is less than the old value");
_values[index] = newValue;
int parent = (index - 1) / 2;
while( index > 0 && _values[parent] < _values[index] )
{
Swap(parent,index);
index = parent;
parent = (index - 1) / 2;
}
}
void Print() const
{
cout << "Size=" << _size << endl;
for(int i=0;i<_size;++i)
{
cout << _values[i] << ",";
}
cout << endl;
}
private:
T* _values;
int _size;
void MaxHeapify(int low, int high)
{
if(low < high)
{
int large = low*2+1;
while( large <= high )
{
if( large < high && _values[large] < _values[large + 1])
++large;
if( _values[low] < _values[large] )
{
Swap(low,large);
low = large;
large = 2*low+1;
}
else
{
break;
}
}
}
}
void Swap(int source, int target)
{
if( source != target )
{
T temp = _values[target];
_values[target] = _values[source];
_values[source] = temp;
}
}
};
#endif
void LargestPriorityQueueTest1()
{
LargestPriorityQueue<int> lpq;
lpq.Print();
lpq.Insert(10);
lpq.Insert(7);
lpq.Insert(15);
lpq.Print();
lpq.Insert(2);
lpq.Print();
lpq.IncreaseKey(3,13);
lpq.Print();
lpq.IncreaseKey(3,18);
lpq.Print();
cout << lpq.GetLargest() << endl;
cout << lpq.RemoveLargest() << endl;
lpq.Print();
}
相对应的,最小优先级队列的代码如下:
#ifndef _SMALLESTPRIORITYQUEUE_
#define _SMALLESTPRIORITYQUEUE_
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T, int MaxCount=100>
class SmallestPriorityQueue
{
public:
SmallestPriorityQueue(): _size(0) { _values = new T[MaxCount]; }
~SmallestPriorityQueue() { delete [] _values; }
SmallestPriorityQueue( const SmallestPriorityQueue& rhs) : _size(0),_values(NULL) { operator=(rhs); }
const SmallestPriorityQueue& operator= ( const SmallestPriorityQueue& rhs)
{
if( this != &rhs )
{
delete [] _values;
_values = new T[MaxCount];
_size = rhs._size;
for(int i=0;i<_size;++i)
_values[i] = rhs._values[i];
}
return *this;
}
bool IsEmpty() const { return _size == 0; }
bool IsFull() const { return _size == MaxCount; }
int Size() const { return _size; }
void Insert(const T& value)
{
if(IsFull())
throw logic_error("Queue is full");
_values[_size++] = value;
int index = _size-1;
int parent = (index-1) /2;
while( index>0 && _values[index] < _values[parent] )
{
Swap(index,parent);
index = parent;
parent = (index-1) /2;
}
}
T GetSmallest()
{
if(IsEmpty())
throw logic_error("No element in the queue");
return _values[0];
}
T RemoveSmallest()
{
if(IsEmpty())
throw logic_error("No element in the queue");
T value = _values[0];
Swap(0,_size-1);
--_size;
MinHeapify(0,_size-1);
return value;
}
void DecreaseKey(int index, const T& newValue)
{
if( index < 0 || index >= _size )
throw logic_error("Invalid index value");
if( _values[index] < newValue )
throw logic_error("New value is greater than the old value");
_values[index] = newValue;
int parent = (index - 1) / 2;
while( index>0 && _values[index] < _values[parent] )
{
Swap(index,parent);
index = parent;
parent = (index-1) /2;
}
}
void Print() const
{
cout << "Size=" << _size << endl;
for(int i=0;i<_size;++i)
{
cout << _values[i] << ",";
}
cout << endl;
}
private :
void MinHeapify(int low, int high)
{
if(low < high)
{
int small = low*2+1;
while( small <= high )
{
if( small < high && _values[small] > _values[small + 1])
++small;
if( _values[low] > _values[small] )
{
Swap(low,small);
low = small;
small = 2*low+1;
}
else
{
break;
}
}
}
}
void Swap(int source, int target)
{
if( source != target )
{
T temp = _values[target];
_values[target] = _values[source];
_values[source] = temp;
}
}
T* _values;
int _size;
};
#endif
测试代码如下:
void SmallestPriorityQueueTest1()
{
SmallestPriorityQueue<int> spq;
spq.Print();
spq.Insert(12);
spq.Insert(9);
spq.Insert(10);
spq.Print();
spq.Insert(4);
spq.Print();
spq.DecreaseKey(3,2);
spq.Print();
spq.Insert(7);
spq.Print();
cout << spq.GetSmallest() << endl;
cout << spq.RemoveSmallest() << endl;
spq.Print();
while( spq.Size() > 0)
{
cout << spq.RemoveSmallest() << endl;
}
spq.Print();
}