# 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 */