# binaryheap.hpp

Go to the documentation of this file.

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