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