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   FORCEINLINE 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   FORCEINLINE 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   FORCEINLINE 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   FORCEINLINE uint Length() const { return this->items; }
00161 
00167   FORCEINLINE bool IsEmpty() const { return this->items == 0; }
00168 
00174   FORCEINLINE bool IsFull() const { return this->items >= this->capacity; }
00175 
00181   FORCEINLINE T *Begin()
00182   {
00183     assert(!this->IsEmpty());
00184     return this->data[1];
00185   }
00186 
00194   FORCEINLINE T *End()
00195   {
00196     return this->data[1 + this->items];
00197   }
00198 
00204   FORCEINLINE void Include(T *new_item)
00205   {
00206     if (this->IsFull()) {
00207       this->capacity *= 2;
00208       this->data = ReallocT<T*>(this->data, this->capacity + 1);
00209     }
00210 
00211     /* Make place for new item. A gap is now at the end of the tree. */
00212     uint gap = this->HeapifyUp(++items, new_item);
00213     this->data[gap] = new_item;
00214     CHECK_CONSISTY();
00215   }
00216 
00223   FORCEINLINE T *Shift()
00224   {
00225     assert(!this->IsEmpty());
00226 
00227     T *first = this->Begin();
00228 
00229     this->items--;
00230     /* at index 1 we have a gap now */
00231     T *last = this->End();
00232     uint gap = this->HeapifyDown(1, last);
00233     /* move last item to the proper place */
00234     if (!this->IsEmpty()) this->data[gap] = last;
00235 
00236     CHECK_CONSISTY();
00237     return first;
00238   }
00239 
00245   FORCEINLINE void Remove(uint index)
00246   {
00247     if (index < this->items) {
00248       assert(index != 0);
00249       this->items--;
00250       /* at position index we have a gap now */
00251 
00252       T *last = this->End();
00253       /* Fix binary tree up and downwards */
00254       uint gap = this->HeapifyUp(index, last);
00255       gap = this->HeapifyDown(gap, last);
00256       /* move last item to the proper place */
00257       if (!this->IsEmpty()) this->data[gap] = last;
00258     } else {
00259       assert(index == this->items);
00260       this->items--;
00261     }
00262     CHECK_CONSISTY();
00263   }
00264 
00273   FORCEINLINE uint FindIndex(const T &item) const
00274   {
00275     if (this->IsEmpty()) return 0;
00276     for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) {
00277       if (*ppI == &item) {
00278         return ppI - this->data;
00279       }
00280     }
00281     return 0;
00282   }
00283 
00288   FORCEINLINE void Clear() { this->items = 0; }
00289 };
00290 
00291 #endif /* BINARYHEAP_HPP */

Generated on Fri Jun 3 05:18:52 2011 for OpenTTD by  doxygen 1.6.1