binaryheap.hpp

Go to the documentation of this file.
00001 /* $Id: binaryheap.hpp 21594 2010-12-22 11:24:38Z alberth $ */
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 
00017 /* Enable it if you suspect binary heap doesn't work well */
00018 #define BINARYHEAP_CHECK 0
00019 
00020 #if BINARYHEAP_CHECK
00021   #define CHECK_CONSISTY() this->CheckConsistency()
00022 #else
00023   #define CHECK_CONSISTY() ;
00024 #endif
00025 
00050 template <class T>
00051 class CBinaryHeapT {
00052 private:
00053   uint items;    
00054   uint capacity; 
00055   T **data;      
00056 
00057 public:
00058   explicit CBinaryHeapT(uint max_items)
00059     : items(0)
00060     , capacity(max_items)
00061   {
00062     this->data = MallocT<T *>(max_items + 1);
00063   }
00064 
00065   ~CBinaryHeapT()
00066   {
00067     this->Clear();
00068     free(this->data);
00069     this->data = NULL;
00070   }
00071 
00072 protected:
00082   FORCEINLINE uint HeapifyDown(uint gap, T *item)
00083   {
00084     assert(gap != 0);
00085 
00086     /* The first child of the gap is at [parent * 2] */
00087     uint child = gap * 2;
00088 
00089     /* while children are valid */
00090     while (child <= this->items) {
00091       /* choose the smaller child */
00092       if (child < this->items && *this->data[child + 1] < *this->data[child]) {
00093         child++;
00094       }
00095       /* is it smaller than our parent? */
00096       if (!(*this->data[child] < *item)) {
00097         /* the smaller child is still bigger or same as parent => we are done */
00098         break;
00099       }
00100       /* if smaller child is smaller than parent, it will become new parent */
00101       this->data[gap] = this->data[child];
00102       gap = child;
00103       /* where do we have our new children? */
00104       child = gap * 2;
00105     }
00106     return gap;
00107   }
00108 
00118   FORCEINLINE uint HeapifyUp(uint gap, T *item)
00119   {
00120     assert(gap != 0);
00121 
00122     uint parent;
00123 
00124     while (gap > 1) {
00125       /* compare [gap] with its parent */
00126       parent = gap / 2;
00127       if (!(*item < *this->data[parent])) {
00128         /* we don't need to continue upstairs */
00129         break;
00130       }
00131       this->data[gap] = this->data[parent];
00132       gap = parent;
00133     }
00134     return gap;
00135   }
00136 
00137 #if BINARYHEAP_CHECK
00138 
00139   FORCEINLINE void CheckConsistency()
00140   {
00141     for (uint child = 2; child <= this->items; child++) {
00142       uint parent = child / 2;
00143       assert(!(*this->data[child] < *this->data[parent]));
00144     }
00145   }
00146 #endif
00147 
00148 public:
00154   FORCEINLINE uint Length() const { return this->items; }
00155 
00161   FORCEINLINE bool IsEmpty() const { return this->items == 0; }
00162 
00168   FORCEINLINE bool IsFull() const { return this->items >= this->capacity; }
00169 
00175   FORCEINLINE T *Begin()
00176   {
00177     assert(!this->IsEmpty());
00178     return this->data[1];
00179   }
00180 
00188   FORCEINLINE T *End()
00189   {
00190     return this->data[1 + this->items];
00191   }
00192 
00198   FORCEINLINE void Include(T *new_item)
00199   {
00200     if (this->IsFull()) {
00201       this->capacity *= 2;
00202       this->data = ReallocT<T*>(this->data, this->capacity + 1);
00203     }
00204 
00205     /* Make place for new item. A gap is now at the end of the tree. */
00206     uint gap = this->HeapifyUp(++items, new_item);
00207     this->data[gap] = new_item;
00208     CHECK_CONSISTY();
00209   }
00210 
00217   FORCEINLINE T *Shift()
00218   {
00219     assert(!this->IsEmpty());
00220 
00221     T *first = this->Begin();
00222 
00223     this->items--;
00224     /* at index 1 we have a gap now */
00225     T *last = this->End();
00226     uint gap = this->HeapifyDown(1, last);
00227     /* move last item to the proper place */
00228     if (!this->IsEmpty()) this->data[gap] = last;
00229 
00230     CHECK_CONSISTY();
00231     return first;
00232   }
00233 
00239   FORCEINLINE void Remove(uint index)
00240   {
00241     if (index < this->items) {
00242       assert(index != 0);
00243       this->items--;
00244       /* at position index we have a gap now */
00245 
00246       T *last = this->End();
00247       /* Fix binary tree up and downwards */
00248       uint gap = this->HeapifyUp(index, last);
00249       gap = this->HeapifyDown(gap, last);
00250       /* move last item to the proper place */
00251       if (!this->IsEmpty()) this->data[gap] = last;
00252     } else {
00253       assert(index == this->items);
00254       this->items--;
00255     }
00256     CHECK_CONSISTY();
00257   }
00258 
00267   FORCEINLINE uint FindIndex(const T &item) const
00268   {
00269     if (this->IsEmpty()) return 0;
00270     for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) {
00271       if (*ppI == &item) {
00272         return ppI - this->data;
00273       }
00274     }
00275     return 0;
00276   }
00277 
00282   FORCEINLINE void Clear() { this->items = 0; }
00283 };
00284 
00285 #endif /* BINARYHEAP_HPP */

Generated on Fri Mar 4 21:37:00 2011 for OpenTTD by  doxygen 1.6.1