460 lines
11 KiB
C++
460 lines
11 KiB
C++
// Copyright (c) 1994 Darren Erik Vengroff
|
|
//
|
|
// File: pqueue_heap.h
|
|
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
|
// Created: 10/4/94
|
|
//
|
|
// $Id: pqueue_heap.h,v 1.10 2005/01/14 18:36:24 tavi Exp $
|
|
//
|
|
// A priority queue class implemented as a binary heap.
|
|
//
|
|
|
|
#ifndef _PQUEUE_HEAP_H
|
|
#define _PQUEUE_HEAP_H
|
|
|
|
// Get definitions for working with Unix and Windows
|
|
#include "u/nvasil/tpie/portability.h"
|
|
|
|
// The virtual base class that defines what priority queues must do.
|
|
template <class T, class P>
|
|
class pqueue
|
|
{
|
|
public:
|
|
// Is it full?
|
|
virtual bool full(void) = 0;
|
|
|
|
// How many elements?
|
|
virtual unsigned int num_elts(void) = 0;
|
|
|
|
// Insert
|
|
virtual bool insert(const T& elt, const P& prio) = 0;
|
|
|
|
// Min
|
|
virtual void get_min(T& elt, P& prio) = 0;
|
|
|
|
// Extract min.
|
|
virtual bool extract_min(T& elt, P& prio) = 0;
|
|
};
|
|
|
|
|
|
// Helper functions for navigating through a binary heap.
|
|
|
|
// The children of an element of the heap.
|
|
|
|
static inline unsigned int lchild(unsigned int index) {
|
|
return 2 * index;
|
|
}
|
|
|
|
static inline unsigned int rchild(unsigned int index) {
|
|
return 2 * index + 1;
|
|
}
|
|
|
|
// The parent of an element.
|
|
|
|
static inline unsigned int parent(unsigned int index) {
|
|
return index >> 1;
|
|
}
|
|
|
|
template <class T, class P>
|
|
struct q_elt {
|
|
T elt;
|
|
P priority;
|
|
};
|
|
|
|
|
|
// A base class for priority queues that use heaps.
|
|
|
|
template <class T, class P>
|
|
class pqueue_heap
|
|
{
|
|
protected:
|
|
// A pointer to the array of elements and their priorities.
|
|
q_elt<T,P> * elements;
|
|
|
|
// The number currently in the queue.
|
|
unsigned int cur_elts;
|
|
|
|
// The maximum number the queue can hold.
|
|
unsigned int max_elts;
|
|
|
|
// Fix up the heap after a deletion.
|
|
/* virtual void heapify(unsigned int root) = 0; */
|
|
|
|
public:
|
|
pqueue_heap(unsigned int size);
|
|
|
|
virtual ~pqueue_heap();
|
|
|
|
// Is it full?
|
|
bool full(void);
|
|
|
|
// How many elements?
|
|
unsigned int num_elts(void);
|
|
|
|
// Min
|
|
void get_min(T& elt, P& prio);
|
|
|
|
};
|
|
|
|
|
|
template <class T, class P>
|
|
pqueue_heap<T,P>::pqueue_heap(unsigned int size)
|
|
{
|
|
elements = new q_elt<T,P>[max_elts = size];
|
|
cur_elts = 0;
|
|
}
|
|
|
|
template <class T, class P>
|
|
pqueue_heap<T,P>::~pqueue_heap() {
|
|
delete [] elements;
|
|
cur_elts = 0;
|
|
max_elts = 0;
|
|
return;
|
|
}
|
|
|
|
template <class T, class P>
|
|
bool pqueue_heap<T,P>::full(void) {
|
|
return cur_elts == max_elts;
|
|
}
|
|
|
|
template <class T, class P>
|
|
unsigned int pqueue_heap<T,P>::num_elts(void) {
|
|
return cur_elts;
|
|
}
|
|
|
|
template <class T, class P>
|
|
void pqueue_heap<T,P>::get_min(T& elt, P& prio) {
|
|
elt = elements->elt;
|
|
prio = elements->priority;
|
|
}
|
|
|
|
|
|
// Comment: (jan) You must not use this version anymore.
|
|
|
|
// // A priority queue that uses a comparison function for comparing
|
|
// // priorities.
|
|
|
|
// End Comment.
|
|
|
|
|
|
// A priority queue that uses the builtin operator < for comparing
|
|
// priorities instead of a comparison function.
|
|
|
|
template <class T, class P>
|
|
class pqueue_heap_op : public pqueue_heap<T,P>
|
|
{
|
|
private:
|
|
void heapify(unsigned int root);
|
|
protected:
|
|
using pqueue_heap<T,P>::cur_elts;
|
|
using pqueue_heap<T,P>::max_elts;
|
|
using pqueue_heap<T,P>::elements;
|
|
|
|
public:
|
|
using pqueue_heap<T,P>::full;
|
|
using pqueue_heap<T,P>::num_elts;
|
|
|
|
pqueue_heap_op(unsigned int size);
|
|
virtual ~pqueue_heap_op(void) {};
|
|
|
|
// Insert
|
|
bool insert(const T& elt, const P& prio);
|
|
// Extract min.
|
|
bool extract_min(T& elt, P& prio);
|
|
};
|
|
|
|
template <class T, class P>
|
|
bool pqueue_heap_op<T,P>::extract_min(T& elt, P& prio) {
|
|
if (!cur_elts) {
|
|
return false;
|
|
}
|
|
elt = elements->elt;
|
|
prio = elements->priority;
|
|
elements[0] = elements[--cur_elts];
|
|
heapify(0);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class T, class P>
|
|
pqueue_heap_op<T,P>::pqueue_heap_op(unsigned int size) :
|
|
pqueue_heap<T,P>(size)
|
|
{
|
|
}
|
|
|
|
|
|
template <class T, class P>
|
|
bool pqueue_heap_op<T,P>::insert(const T& elt, const P& prio) {
|
|
unsigned int ii;
|
|
|
|
if (full()) {
|
|
return false;
|
|
}
|
|
|
|
for (ii = cur_elts++;
|
|
ii && (elements[parent(ii)].priority > prio);
|
|
ii = parent(ii)) {
|
|
elements[ii] = elements[parent(ii)];
|
|
}
|
|
elements[ii].priority = prio;
|
|
elements[ii].elt = elt;
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class T, class P>
|
|
void pqueue_heap_op<T,P>::heapify(unsigned int root) {
|
|
unsigned int min_index = root;
|
|
unsigned int lc = lchild(root);
|
|
unsigned int rc = rchild(root);
|
|
|
|
if ((lc < cur_elts) && (elements[lc].priority <
|
|
elements[min_index].priority)) {
|
|
min_index = lc;
|
|
}
|
|
if ((rc < cur_elts) && (elements[rc].priority <
|
|
elements[min_index].priority)) {
|
|
min_index = rc;
|
|
}
|
|
|
|
if (min_index != root) {
|
|
q_elt<T,P> tmp_q = elements[min_index];
|
|
|
|
elements[min_index] = elements[root];
|
|
elements[root] = tmp_q;
|
|
|
|
heapify(min_index);
|
|
}
|
|
}
|
|
|
|
// A priority queue that uses a comparison object.
|
|
|
|
template <class T, class P, class CMPR>
|
|
class pqueue_heap_obj : public pqueue_heap<T,P>
|
|
{
|
|
private:
|
|
CMPR *cmp_o;
|
|
void heapify(unsigned int root);
|
|
protected:
|
|
using pqueue_heap<T,P>::cur_elts;
|
|
using pqueue_heap<T,P>::max_elts;
|
|
using pqueue_heap<T,P>::elements;
|
|
|
|
public:
|
|
using pqueue_heap<T,P>::full;
|
|
using pqueue_heap<T,P>::num_elts;
|
|
|
|
public:
|
|
pqueue_heap_obj(unsigned int size, CMPR *cmp);
|
|
virtual ~pqueue_heap_obj(void) {};
|
|
|
|
// Insert
|
|
bool insert(const T& elt, const P& prio);
|
|
// Extract min.
|
|
bool extract_min(T& elt, P& prio);
|
|
};
|
|
|
|
template <class T, class P, class CMPR>
|
|
bool pqueue_heap_obj<T,P,CMPR>::extract_min(T& elt, P& prio) {
|
|
if (!cur_elts) {
|
|
return false;
|
|
}
|
|
elt = elements->elt;
|
|
prio = elements->priority;
|
|
elements[0] = elements[--cur_elts];
|
|
heapify(0);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class T, class P, class CMPR>
|
|
pqueue_heap_obj<T,P,CMPR>::pqueue_heap_obj(unsigned int size, CMPR *cmp)
|
|
: pqueue_heap<T,P>(size)
|
|
|
|
{
|
|
cmp_o = cmp;
|
|
}
|
|
|
|
|
|
template <class T, class P, class CMPR>
|
|
bool pqueue_heap_obj<T,P,CMPR>::insert(const T& elt, const P& prio) {
|
|
unsigned int ii;
|
|
|
|
if (full()) {
|
|
return false;
|
|
}
|
|
|
|
for (ii = cur_elts++;
|
|
ii && (cmp_o->compare(elements[parent(ii)].priority, prio) > 0);
|
|
ii = parent(ii)) {
|
|
elements[ii] = elements[parent(ii)];
|
|
}
|
|
elements[ii].priority = prio;
|
|
elements[ii].elt = elt;
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class T, class P, class CMPR>
|
|
void pqueue_heap_obj<T,P,CMPR>::heapify(unsigned int root) {
|
|
unsigned int min_index = root;
|
|
unsigned int lc = lchild(root);
|
|
unsigned int rc = rchild(root);
|
|
|
|
if ((lc < cur_elts) &&
|
|
(cmp_o->compare(elements[lc].priority,
|
|
elements[min_index].priority) < 0)) {
|
|
min_index = lc;
|
|
}
|
|
if ((rc < cur_elts) &&
|
|
(cmp_o->compare(elements[rc].priority,
|
|
elements[min_index].priority) < 0)) {
|
|
min_index = rc;
|
|
}
|
|
|
|
if (min_index != root) {
|
|
q_elt<T,P> tmp_q = elements[min_index];
|
|
|
|
elements[min_index] = elements[root];
|
|
elements[root] = tmp_q;
|
|
|
|
heapify(min_index);
|
|
}
|
|
}
|
|
|
|
|
|
// Comment: (jan) You must not use this version anymore.
|
|
|
|
template <class T, class P>
|
|
class pqueue_heap_cmp : public pqueue_heap<T,P>
|
|
{
|
|
|
|
private:
|
|
// A pointer to the function used to compare the priorities of
|
|
// elements.
|
|
int (*cmp_f)(const P&, const P&);
|
|
void heapify(unsigned int root);
|
|
protected:
|
|
using pqueue_heap<T,P>::cur_elts;
|
|
using pqueue_heap<T,P>::max_elts;
|
|
using pqueue_heap<T,P>::elements;
|
|
public:
|
|
using pqueue_heap<T,P>::full;
|
|
using pqueue_heap<T,P>::num_elts;
|
|
|
|
public:
|
|
pqueue_heap_cmp(unsigned int size, int (*cmp)(const P&, const P&));
|
|
virtual ~pqueue_heap_cmp(void) {}
|
|
// Insert
|
|
bool insert(const T& elt, const P& prio);
|
|
// Extract min.
|
|
bool extract_min(T& elt, P& prio);
|
|
};
|
|
|
|
|
|
template <class T, class P>
|
|
bool pqueue_heap_cmp<T,P>::extract_min(T& elt, P& prio)
|
|
{
|
|
|
|
if (!cur_elts) {
|
|
return false;
|
|
}
|
|
|
|
elt = elements->elt;
|
|
prio = elements->priority;
|
|
elements[0] = elements[--cur_elts];
|
|
heapify(0);
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
template <class T, class P>
|
|
pqueue_heap_cmp<T,P>::pqueue_heap_cmp(unsigned int size,
|
|
int (*cmp)(const P&, const P&)) :
|
|
pqueue_heap<T,P>(size) {
|
|
cmp_f = cmp;
|
|
}
|
|
|
|
|
|
|
|
template <class T, class P>
|
|
bool pqueue_heap_cmp<T,P>::insert(const T& elt, const P& prio)
|
|
{
|
|
unsigned int ii;
|
|
if (full()) {
|
|
return false;
|
|
}
|
|
|
|
|
|
for (ii = cur_elts++;
|
|
ii && (cmp_f(elements[parent(ii)].priority, prio) > 0);
|
|
ii = parent(ii))
|
|
{
|
|
|
|
elements[ii] = elements[parent(ii)];
|
|
|
|
}
|
|
|
|
elements[ii].priority = prio;
|
|
|
|
elements[ii].elt = elt;
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
template <class T, class P>
|
|
void pqueue_heap_cmp<T,P>::heapify(unsigned int root)
|
|
{
|
|
|
|
unsigned int min_index = root;
|
|
|
|
unsigned int lc = lchild(root);
|
|
|
|
unsigned int rc = rchild(root);
|
|
|
|
|
|
if ((lc < cur_elts) && (cmp_f(elements[lc].priority,
|
|
elements[min_index].priority) < 0))
|
|
{
|
|
|
|
min_index = lc;
|
|
|
|
}
|
|
|
|
if ((rc < cur_elts) && (cmp_f(elements[rc].priority,
|
|
elements[min_index].priority) < 0))
|
|
{
|
|
|
|
min_index = rc;
|
|
|
|
}
|
|
|
|
|
|
if (min_index != root)
|
|
{
|
|
|
|
q_elt<T,P> tmp_q = elements[min_index];
|
|
|
|
|
|
elements[min_index] = elements[root];
|
|
|
|
elements[root] = tmp_q;
|
|
|
|
|
|
heapify(min_index);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// // A priority queue that simply uses an array.
|
|
|
|
// End Comment.
|
|
|
|
#endif // _PQUEUE_HEAP_H
|