#ifndef _pqueue_h
#define _pqueue_h
#include "vector.h"
template <typename ValueType>
class PriorityQueue {
public:
PriorityQueue();
virtual ~PriorityQueue();
int size() const;
bool isEmpty() const;
void clear();
void enqueue(ValueType value, double priority);
ValueType dequeue();
ValueType peek() const;
double peekPriority() const;
ValueType & front();
ValueType & back();
std::string toString();
private:
struct HeapEntry {
ValueType value;
double priority;
long sequence;
};
Vector<HeapEntry> heap;
long enqueueCount;
int backIndex;
int count;
int capacity;
void enqueueHeap(ValueType & value, double priority);
ValueType dequeueHeap();
bool takesPriority(int i1, int i2);
void swapHeapEntries(int i1, int i2);
};
extern void error(std::string msg);
template <typename ValueType>
PriorityQueue<ValueType>::PriorityQueue() {
clear();
}
template <typename ValueType>
PriorityQueue<ValueType>::~PriorityQueue() {
}
template <typename ValueType>
int PriorityQueue<ValueType>::size() const {
return count;
}
template <typename ValueType>
bool PriorityQueue<ValueType>::isEmpty() const {
return count == 0;
}
template <typename ValueType>
void PriorityQueue<ValueType>::clear() {
heap.clear();
count = 0;
}
template <typename ValueType>
void PriorityQueue<ValueType>::enqueue(ValueType value, double priority) {
if (count == heap.size()) heap.add(HeapEntry());
int index = count++;
heap[index].value = value;
heap[index].priority = priority;
heap[index].sequence = enqueueCount++;
if (index == 0 || takesPriority(backIndex, index)) backIndex = index;
while (index > 0) {
int parent = (index - 1) / 2;
if (takesPriority(parent, index)) break;
swapHeapEntries(parent, index);
index = parent;
}
}
template <typename ValueType>
ValueType PriorityQueue<ValueType>::dequeue() {
if (count == 0) error("dequeue: Attempting to dequeue an empty queue");
count--;
bool wasBack = (backIndex == count);
ValueType value = heap[0].value;
swapHeapEntries(0, count);
int index = 0;
while (true) {
int left = 2 * index + 1;
int right = 2 * index + 2;
if (left >= count) break;
int child = left;
if (right < count && takesPriority(right, left)) child = right;
if (takesPriority(index, child)) break;
swapHeapEntries(index, child);
index = child;
}
if (wasBack) backIndex = index;
return value;
}
template <typename ValueType>
ValueType PriorityQueue<ValueType>::peek() const {
if (count == 0) error("peek: Attempting to peek at an empty queue");
return heap.get(0).value;
}
template <typename ValueType>
double PriorityQueue<ValueType>::peekPriority() const {
if (count == 0) error("peekPriority: Attempting to peek at an empty queue");
return heap.get(0).priority;
}
template <typename ValueType>
ValueType & PriorityQueue<ValueType>::front() {
if (count == 0) error("front: Attempting to read front of an empty queue");
return heap.get(0).value;
}
template <typename ValueType>
ValueType & PriorityQueue<ValueType>::back() {
if (count == 0) error("back: Attempting to read back of an empty queue");
return heap.get(backIndex).value;
}
template <typename ValueType>
bool PriorityQueue<ValueType>::takesPriority(int i1, int i2) {
if (heap[i1].priority < heap[i2].priority) return true;
if (heap[i1].priority > heap[i2].priority) return false;
return (heap[i1].sequence < heap[i2].sequence);
}
template <typename ValueType>
void PriorityQueue<ValueType>::swapHeapEntries(int i1, int i2) {
HeapEntry entry = heap[i1];
heap[i1] = heap[i2];
heap[i2] = entry;
}
template <typename ValueType>
std::string PriorityQueue<ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
template <typename ValueType>
std::ostream & operator<<(std::ostream & os,
const PriorityQueue<ValueType> & pq) {
os << "{";
PriorityQueue<ValueType> copy = pq;
int len = pq.size();
for (int i = 0; i < len; i++) {
if (i > 0) os << ", ";
os << copy.peekPriority() << ":";
writeGenericValue(os, copy.dequeue(), true);
}
return os << "}";
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, PriorityQueue<ValueType> & pq) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
pq.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
double priority;
is >> priority >> ch;
if (ch != ':') error("operator >>: Missing colon after priority");
ValueType value;
readGenericValue(is, value);
pq.enqueue(value, priority);
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
#endif