binaryheap.hpp

Go to the documentation of this file.
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 */

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6