binaryheap.hpp

Go to the documentation of this file.
00001 /* $Id$ */
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 
00015 #include "../core/alloc_func.hpp"
00016 
00018 #define BINARYHEAP_CHECK 0
00019 
00020 #if BINARYHEAP_CHECK
00021 
00022   #define CHECK_CONSISTY() this->CheckConsistency()
00023 #else
00024 
00025   #define CHECK_CONSISTY() ;
00026 #endif
00027 
00052 template <class T>
00053 class CBinaryHeapT {
00054 private:
00055   uint items;    
00056   uint capacity; 
00057   T **data;      
00058 
00059 public:
00064   explicit CBinaryHeapT(uint max_items)
00065     : items(0)
00066     , capacity(max_items)
00067   {
00068     this->data = MallocT<T *>(max_items + 1);
00069   }
00070 
00071   ~CBinaryHeapT()
00072   {
00073     this->Clear();
00074     free(this->data);
00075     this->data = NULL;
00076   }
00077 
00078 protected:
00088   inline uint HeapifyDown(uint gap, T *item)
00089   {
00090     assert(gap != 0);
00091 
00092     /* The first child of the gap is at [parent * 2] */
00093     uint child = gap * 2;
00094 
00095     /* while children are valid */
00096     while (child <= this->items) {
00097       /* choose the smaller child */
00098       if (child < this->items && *this->data[child + 1] < *this->data[child]) {
00099         child++;
00100       }
00101       /* is it smaller than our parent? */
00102       if (!(*this->data[child] < *item)) {
00103         /* the smaller child is still bigger or same as parent => we are done */
00104         break;
00105       }
00106       /* if smaller child is smaller than parent, it will become new parent */
00107       this->data[gap] = this->data[child];
00108       gap = child;
00109       /* where do we have our new children? */
00110       child = gap * 2;
00111     }
00112     return gap;
00113   }
00114 
00124   inline uint HeapifyUp(uint gap, T *item)
00125   {
00126     assert(gap != 0);
00127 
00128     uint parent;
00129 
00130     while (gap > 1) {
00131       /* compare [gap] with its parent */
00132       parent = gap / 2;
00133       if (!(*item < *this->data[parent])) {
00134         /* we don't need to continue upstairs */
00135         break;
00136       }
00137       this->data[gap] = this->data[parent];
00138       gap = parent;
00139     }
00140     return gap;
00141   }
00142 
00143 #if BINARYHEAP_CHECK
00144 
00145   inline void CheckConsistency()
00146   {
00147     for (uint child = 2; child <= this->items; child++) {
00148       uint parent = child / 2;
00149       assert(!(*this->data[child] < *this->data[parent]));
00150     }
00151   }
00152 #endif
00153 
00154 public:
00160   inline uint Length() const { return this->items; }
00161 
00167   inline bool IsEmpty() const { return this->items == 0; }
00168 
00174   inline bool IsFull() const { return this->items >= this->capacity; }
00175 
00181   inline T *Begin()
00182   {
00183     assert(!this->IsEmpty());
00184     return this->data[1];
00185   }
00186 
00194   inline T *End()
00195   {
00196     return this->data[1 + this->items];
00197   }
00198 
00204   inline void Include(T *new_item)
00205   {
00206     if (this->IsFull()) {
00207       assert(this->capacity < UINT_MAX / 2);
00208 
00209       this->capacity *= 2;
00210       this->data = ReallocT<T*>(this->data, this->capacity + 1);
00211     }
00212 
00213     /* Make place for new item. A gap is now at the end of the tree. */
00214     uint gap = this->HeapifyUp(++items, new_item);
00215     this->data[gap] = new_item;
00216     CHECK_CONSISTY();
00217   }
00218 
00225   inline T *Shift()
00226   {
00227     assert(!this->IsEmpty());
00228 
00229     T *first = this->Begin();
00230 
00231     this->items--;
00232     /* at index 1 we have a gap now */
00233     T *last = this->End();
00234     uint gap = this->HeapifyDown(1, last);
00235     /* move last item to the proper place */
00236     if (!this->IsEmpty()) this->data[gap] = last;
00237 
00238     CHECK_CONSISTY();
00239     return first;
00240   }
00241 
00247   inline void Remove(uint index)
00248   {
00249     if (index < this->items) {
00250       assert(index != 0);
00251       this->items--;
00252       /* at position index we have a gap now */
00253 
00254       T *last = this->End();
00255       /* Fix binary tree up and downwards */
00256       uint gap = this->HeapifyUp(index, last);
00257       gap = this->HeapifyDown(gap, last);
00258       /* move last item to the proper place */
00259       if (!this->IsEmpty()) this->data[gap] = last;
00260     } else {
00261       assert(index == this->items);
00262       this->items--;
00263     }
00264     CHECK_CONSISTY();
00265   }
00266 
00275   inline uint FindIndex(const T &item) const
00276   {
00277     if (this->IsEmpty()) return 0;
00278     for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) {
00279       if (*ppI == &item) {
00280         return ppI - this->data;
00281       }
00282     }
00283     return 0;
00284   }
00285 
00290   inline void Clear() { this->items = 0; }
00291 };
00292 
00293 #endif /* BINARYHEAP_HPP */