binaryheap.hpp

Go to the documentation of this file.
00001 /* $Id: binaryheap.hpp 17248 2009-08-21 20:21:05Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #ifndef  BINARYHEAP_HPP
00013 #define  BINARYHEAP_HPP
00014 
00033 template <class Titem_>
00034 class CBinaryHeapT {
00035 public:
00036   typedef Titem_ *ItemPtr;
00037 private:
00038   int                     m_size;     
00039   int                     m_max_size; 
00040   ItemPtr                *m_items;    
00041 
00042 public:
00043   explicit CBinaryHeapT(int max_items = 102400)
00044     : m_size(0)
00045     , m_max_size(max_items)
00046   {
00047     m_items = new ItemPtr[max_items + 1];
00048   }
00049 
00050   ~CBinaryHeapT()
00051   {
00052     Clear();
00053     delete [] m_items;
00054     m_items = NULL;
00055   }
00056 
00057 public:
00060   FORCEINLINE int Size() const {return m_size;};
00061 
00064   FORCEINLINE bool IsEmpty() const {return (m_size == 0);};
00065 
00068   FORCEINLINE bool IsFull() const {return (m_size >= m_max_size);};
00069 
00072   FORCEINLINE Titem_& GetHead() {assert(!IsEmpty()); return *m_items[1];}
00073 
00076   bool Push(Titem_& new_item);
00077 
00079   FORCEINLINE Titem_& PopHead() {Titem_& ret = GetHead(); RemoveHead(); return ret;};
00080 
00082   void RemoveHead();
00083 
00085   void RemoveByIdx(int idx);
00086 
00088   int FindLinear(const Titem_& item) const;
00089 
00092   void Clear() {m_size = 0;};
00093 
00095   void CheckConsistency();
00096 };
00097 
00098 
00099 template <class Titem_>
00100 FORCEINLINE bool CBinaryHeapT<Titem_>::Push(Titem_& new_item)
00101 {
00102   if (IsFull()) return false;
00103 
00104   /* make place for new item */
00105   int gap = ++m_size;
00106   /* Heapify up */
00107   for (int parent = gap / 2; (parent > 0) && (new_item < *m_items[parent]); gap = parent, parent /= 2)
00108     m_items[gap] = m_items[parent];
00109   m_items[gap] = &new_item;
00110   CheckConsistency();
00111   return true;
00112 }
00113 
00114 template <class Titem_>
00115 FORCEINLINE void CBinaryHeapT<Titem_>::RemoveHead()
00116 {
00117   assert(!IsEmpty());
00118 
00119   /* at index 1 we have a gap now */
00120   int gap = 1;
00121 
00122   /* Heapify down:
00123    *   last item becomes a candidate for the head. Call it new_item. */
00124   Titem_& new_item = *m_items[m_size--];
00125 
00126   /* now we must maintain relation between parent and its children:
00127    *   parent <= any child
00128    * from head down to the tail */
00129   int child  = 2; // first child is at [parent * 2]
00130 
00131   /* while children are valid */
00132   while (child <= m_size) {
00133     /* choose the smaller child */
00134     if (child < m_size && *m_items[child + 1] < *m_items[child])
00135       child++;
00136     /* is it smaller than our parent? */
00137     if (!(*m_items[child] < new_item)) {
00138       /* the smaller child is still bigger or same as parent => we are done */
00139       break;
00140     }
00141     /* if smaller child is smaller than parent, it will become new parent */
00142     m_items[gap] = m_items[child];
00143     gap = child;
00144     /* where do we have our new children? */
00145     child = gap * 2;
00146   }
00147   /* move last item to the proper place */
00148   if (m_size > 0) m_items[gap] = &new_item;
00149   CheckConsistency();
00150 }
00151 
00152 template <class Titem_>
00153 inline void CBinaryHeapT<Titem_>::RemoveByIdx(int idx)
00154 {
00155   /* at position idx we have a gap now */
00156   int gap = idx;
00157   Titem_& last = *m_items[m_size];
00158   if (idx < m_size) {
00159     assert(idx >= 1);
00160     m_size--;
00161     /* and the candidate item for fixing this gap is our last item 'last'
00162      * Move gap / last item up: */
00163     while (gap > 1)
00164     {
00165       /* compare [gap] with its parent */
00166       int parent = gap / 2;
00167       if (last < *m_items[parent]) {
00168         m_items[gap] = m_items[parent];
00169         gap = parent;
00170       } else {
00171         /* we don't need to continue upstairs */
00172         break;
00173       }
00174     }
00175 
00176     /* Heapify (move gap) down: */
00177     while (true) {
00178       /* where we do have our children? */
00179       int child  = gap * 2; // first child is at [parent * 2]
00180       if (child > m_size) break;
00181       /* choose the smaller child */
00182       if (child < m_size && *m_items[child + 1] < *m_items[child])
00183         child++;
00184       /* is it smaller than our parent? */
00185       if (!(*m_items[child] < last)) {
00186         /* the smaller child is still bigger or same as parent => we are done */
00187         break;
00188       }
00189       /* if smaller child is smaller than parent, it will become new parent */
00190       m_items[gap] = m_items[child];
00191       gap = child;
00192     }
00193     /* move parent to the proper place */
00194     if (m_size > 0) m_items[gap] = &last;
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 Sat Jul 17 18:43:18 2010 for OpenTTD by  doxygen 1.6.1