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