00001 /* $Id: binaryheap.hpp 9662 2007-04-17 20:23:13Z belugas $ */ 00002 00005 #ifndef BINARYHEAP_HPP 00006 #define BINARYHEAP_HPP 00007 00008 //void* operator new (size_t size, void* p) {return p;} 00009 #if defined(_MSC_VER) && (_MSC_VER >= 1400) 00010 //void operator delete (void* p, void* p2) {} 00011 #endif 00012 00013 00032 template <class Titem_> 00033 class CBinaryHeapT { 00034 public: 00035 typedef Titem_ *ItemPtr; 00036 private: 00037 int m_size; 00038 int m_max_size; 00039 ItemPtr* m_items; 00040 00041 public: 00042 explicit CBinaryHeapT(int max_items = 102400) 00043 : m_size(0) 00044 , m_max_size(max_items) 00045 { 00046 m_items = new ItemPtr[max_items + 1]; 00047 } 00048 00049 ~CBinaryHeapT() 00050 { 00051 Clear(); 00052 delete [] m_items; 00053 m_items = NULL; 00054 } 00055 00056 public: 00059 FORCEINLINE int Size() const {return m_size;}; 00060 00063 FORCEINLINE bool IsEmpty() const {return (m_size == 0);}; 00064 00067 FORCEINLINE bool IsFull() const {return (m_size >= m_max_size);}; 00068 00071 FORCEINLINE Titem_& GetHead() {assert(!IsEmpty()); return *m_items[1];} 00072 00075 bool Push(Titem_& new_item); 00076 00078 FORCEINLINE Titem_& PopHead() {Titem_& ret = GetHead(); RemoveHead(); return ret;}; 00079 00081 void RemoveHead(); 00082 00084 void RemoveByIdx(int idx); 00085 00087 int FindLinear(const Titem_& item) const; 00088 00091 void Clear() {m_size = 0;}; 00092 00094 void CheckConsistency(); 00095 }; 00096 00097 00098 template <class Titem_> 00099 FORCEINLINE bool CBinaryHeapT<Titem_>::Push(Titem_& new_item) 00100 { 00101 if (IsFull()) return false; 00102 00103 // make place for new item 00104 int gap = ++m_size; 00105 // Heapify up 00106 for (int parent = gap / 2; (parent > 0) && (new_item < *m_items[parent]); gap = parent, parent /= 2) 00107 m_items[gap] = m_items[parent]; 00108 m_items[gap] = &new_item; 00109 CheckConsistency(); 00110 return true; 00111 } 00112 00113 template <class Titem_> 00114 FORCEINLINE void CBinaryHeapT<Titem_>::RemoveHead() 00115 { 00116 assert(!IsEmpty()); 00117 00118 // at index 1 we have a gap now 00119 int gap = 1; 00120 00121 // Heapify down: 00122 // last item becomes a candidate for the head. Call it new_item. 00123 Titem_& new_item = *m_items[m_size--]; 00124 00125 // now we must maintain relation between parent and its children: 00126 // parent <= any child 00127 // from head down to the tail 00128 int child = 2; // first child is at [parent * 2] 00129 00130 // while children are valid 00131 while (child <= m_size) { 00132 // choose the smaller child 00133 if (child < m_size && *m_items[child + 1] < *m_items[child]) 00134 child++; 00135 // is it smaller than our parent? 00136 if (!(*m_items[child] < new_item)) { 00137 // the smaller child is still bigger or same as parent => we are done 00138 break; 00139 } 00140 // if smaller child is smaller than parent, it will become new parent 00141 m_items[gap] = m_items[child]; 00142 gap = child; 00143 // where do we have our new children? 00144 child = gap * 2; 00145 } 00146 // move last item to the proper place 00147 if (m_size > 0) m_items[gap] = &new_item; 00148 CheckConsistency(); 00149 } 00150 00151 template <class Titem_> 00152 inline void CBinaryHeapT<Titem_>::RemoveByIdx(int idx) 00153 { 00154 // at position idx we have a gap now 00155 int gap = idx; 00156 Titem_& last = *m_items[m_size]; 00157 if (idx < m_size) { 00158 assert(idx >= 1); 00159 m_size--; 00160 // and the candidate item for fixing this gap is our last item 'last' 00161 // Move gap / last item up: 00162 while (gap > 1) 00163 { 00164 // compare [gap] with its parent 00165 int parent = gap / 2; 00166 if (last < *m_items[parent]) { 00167 m_items[gap] = m_items[parent]; 00168 gap = parent; 00169 } else { 00170 // we don't need to continue upstairs 00171 break; 00172 } 00173 } 00174 00175 // Heapify (move gap) down: 00176 while (true) { 00177 // where we do have our children? 00178 int child = gap * 2; // first child is at [parent * 2] 00179 if (child > m_size) break; 00180 // choose the smaller child 00181 if (child < m_size && *m_items[child + 1] < *m_items[child]) 00182 child++; 00183 // is it smaller than our parent? 00184 if (!(*m_items[child] < last)) { 00185 // the smaller child is still bigger or same as parent => we are done 00186 break; 00187 } 00188 // if smaller child is smaller than parent, it will become new parent 00189 m_items[gap] = m_items[child]; 00190 gap = child; 00191 } 00192 // move parent to the proper place 00193 if (m_size > 0) m_items[gap] = &last; 00194 } 00195 else { 00196 assert(idx == m_size); 00197 m_size--; 00198 } 00199 CheckConsistency(); 00200 } 00201 00202 template <class Titem_> 00203 inline int CBinaryHeapT<Titem_>::FindLinear(const Titem_& item) const 00204 { 00205 if (IsEmpty()) return 0; 00206 for (ItemPtr *ppI = m_items + 1, *ppLast = ppI + m_size; ppI <= ppLast; ppI++) { 00207 if (*ppI == &item) { 00208 return ppI - m_items; 00209 } 00210 } 00211 return 0; 00212 } 00213 00214 template <class Titem_> 00215 FORCEINLINE void CBinaryHeapT<Titem_>::CheckConsistency() 00216 { 00217 // enable it if you suspect binary heap doesn't work well 00218 #if 0 00219 for (int child = 2; child <= m_size; child++) { 00220 int parent = child / 2; 00221 assert(!(m_items[child] < m_items[parent])); 00222 } 00223 #endif 00224 } 00225 00226 00227 #endif /* BINARYHEAP_HPP */