Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

PriorityQueue.h

Go to the documentation of this file.
00001 // -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002 ////////////////////////////////////////////////////////////////////
00003 //
00004 // Filename : PriorityQueue.h (base)
00005 //
00006 // This file is a part of the UPPAAL toolkit.
00007 // Copyright (c) 1995 - 2003, Uppsala University and Aalborg University.
00008 // All right reserved.
00009 //
00010 // $Id: PriorityQueue.h,v 1.4 2005/04/22 15:20:10 adavid Exp $
00011 //
00012 ///////////////////////////////////////////////////////////////////
00013 
00014 #ifndef INCLUDE_BASE_PRIORITYQUEUE_H
00015 #define INCLUDE_BASE_PRIORITYQUEUE_H
00016 
00017 #include <assert.h>
00018 #include "base/intutils.h"
00019 
00020 namespace base
00021 {
00022     /** This class is here only to protect a variable */
00023     class BasePriorityQueue
00024     {
00025     protected:
00026         /** Update the maximum.
00027          * @param max: maximum.
00028          */
00029         static void updateQueueMax(uint32_t max)
00030         {
00031             if (queueMaxSize < max) queueMaxSize = max;
00032         }
00033 
00034         /** @return the maximum.
00035          */
00036         static uint32_t getQueueMax() { return queueMaxSize; }
00037 
00038     private:
00039         /** This is used to dynamically adjust
00040          * the initial allocated table of elements.
00041          */
00042         static uint32_t queueMaxSize;
00043     };
00044 
00045 
00046     /** Fast, leak free, and controlled priority queue.
00047      * std::priority_queue is 20-30% slower.
00048      * The difference with std::priority_queue is the ordering:
00049      * here it is from lowest to highest, while in std::priority_queue
00050      * it is from highest to lowest.
00051      *
00052      * The element must be sortable and
00053      * have a < comparison operator.
00054      * Elements are copied and never destroyed.
00055      * The algorithm is based on heaps.
00056      * The the Introduction to Algorithms
00057      * 2nd edition p130 for max-heapify and
00058      * p140 for insertion. We use min instead
00059      * of max, so invert the comparisons.
00060      */
00061     template<class T>
00062     class PriorityQueue : protected BasePriorityQueue
00063     {
00064     public:
00065 
00066         /** If we want to have one allocation to fit
00067          * on a page (4k), it is advisable to allocate
00068          * slightly less than 4k for headers.
00069          */
00070         enum { DEC_ALLOC = 16 };
00071 
00072         /** Constructor: initialize the heap (size 0).
00073          */
00074         PriorityQueue()
00075             : capacity(getQueueMax()-DEC_ALLOC),
00076               qsize(0),
00077               table(alloc(capacity))
00078         {
00079             assert(getQueueMax() > DEC_ALLOC);
00080         }
00081 
00082         /** Destructor: update initial size & deallocate
00083          * memory without calling any destructor.
00084          */
00085         ~PriorityQueue()
00086         {
00087             updateQueueMax(capacity+DEC_ALLOC);
00088             delete [] (char*) table;
00089         }
00090         
00091         /** Push an item to the queue.
00092          * Implements min-heap insert (p140).
00093          * The original algorithm uses a swap, but
00094          * it is to propagate the new item.
00095          * @param item: item to push.
00096          * @pre item has a transitive < operator
00097          */
00098         void push(const T& item)
00099         {
00100             ensureCapacity();
00101 
00102             uint32_t k, i = qsize++;
00103             T* t = table;
00104             while(i && item < t[k = ((i-1) >> 1)])
00105             {
00106                 t[i] = t[k];
00107                 i = k;
00108             }
00109             t[i] = item;
00110         }
00111 
00112         /** Read the top element of the queue.
00113          * It is the minimal one with respect to <
00114          */
00115         const T& top() const
00116         {
00117             return table[0];
00118         }
00119 
00120         /** Remove the top element from the queue.
00121          * Implement min-heapify (see max-heapify
00122          * p130: Left(i) == l and Right(i) == l+1).
00123          * @pre !empty()
00124          */
00125         void pop()
00126         {
00127             assert(qsize);
00128             if (--qsize)
00129             {
00130                 uint32_t i = 0;
00131                 T* t = table;
00132                 T* last = &t[qsize];
00133                 if (qsize > 1)
00134                 {
00135                     uint32_t l;
00136                     while(&t[l = (i << 1) + 1] < last)
00137                     {
00138                         uint32_t k =
00139                             &t[l+1] < last && t[l+1] < t[l] ?
00140                             l+1 : l;
00141                         if (t[k] < *last)
00142                         {
00143                             t[i] = t[k];
00144                             i = k;
00145                         }
00146                         else break;
00147                     }
00148                 }
00149                 t[i] = *last;
00150             }
00151         }
00152 
00153         /** @return true if the queue is empty,
00154          * false otherwise.
00155          */
00156         bool empty() const { return qsize == 0; }
00157 
00158         /** @return the size of the queue.
00159          */
00160         uint32_t size() const { return qsize; }
00161 
00162     private:
00163 
00164         /** @return allocated memory for T[n]
00165          * without calling any constructor.
00166          * @param n: number of elements
00167          * @pre T is int padded
00168          */
00169         T* alloc(uint32_t n)
00170         {
00171             assert(sizeof(T)%4 == 0); // int padded
00172             return (T*) new char[sizeof(T[n])];
00173         }
00174 
00175         /** Ensure capacity for a new element to
00176          * be added on the heap.
00177          */
00178         void ensureCapacity()
00179         {
00180             assert(qsize <= capacity);
00181             if (qsize == capacity)
00182             {
00183                 capacity = (capacity << 1) + DEC_ALLOC; // == (capa+dec_alloc)<<1 - dec_alloc
00184                 T *larger = alloc(capacity);
00185                 base_copyLarge(larger, table, intsizeof(T[qsize]));
00186                 delete [] table;
00187                 table = larger;
00188             }
00189         }
00190 
00191         uint32_t capacity; /**< capacity of the heap                 */
00192         uint32_t qsize;    /**< size of the queue                    */
00193         T *table;          /**< table of items with a heap structure */
00194     };
00195 
00196     /** Wrapper for large types: wrap a pointer.
00197      * The large type needs a < comparison operator.
00198      */
00199     template<class T>
00200     class Sortable
00201     {
00202     public:
00203         Sortable(T *p) : ptr(p) {}
00204 
00205         bool operator < (const Sortable<T>& x) const
00206         {
00207             assert(ptr && x.ptr);
00208             return *ptr < *x.ptr;
00209         }
00210 
00211         T *ptr;
00212     };
00213 
00214 } // namespace base
00215 
00216 #endif // INCLUDE_BASE_PRIORITYQUEUE_H

Generated on Fri Jun 30 00:02:30 2006 for Module base by  doxygen 1.4.2