# binaryheap.hpp

Go to the documentation of this file.

    00001 /* $Id: binaryheap.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */
    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 */