OpenTTD
binaryheap.hpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #ifndef BINARYHEAP_HPP
13 #define BINARYHEAP_HPP
14 
15 #include "../core/alloc_func.hpp"
16 
18 #define BINARYHEAP_CHECK 0
19 
20 #if BINARYHEAP_CHECK
21 
22  #define CHECK_CONSISTY() this->CheckConsistency()
23 #else
24 
25  #define CHECK_CONSISTY() ;
26 #endif
27 
52 template <class T>
53 class CBinaryHeapT {
54 private:
55  uint items;
56  uint capacity;
57  T **data;
58 
59 public:
64  explicit CBinaryHeapT(uint max_items)
65  : items(0)
66  , capacity(max_items)
67  {
68  this->data = MallocT<T *>(max_items + 1);
69  }
70 
71  ~CBinaryHeapT()
72  {
73  this->Clear();
74  free(this->data);
75  this->data = NULL;
76  }
77 
78 protected:
88  inline uint HeapifyDown(uint gap, T *item)
89  {
90  assert(gap != 0);
91 
92  /* The first child of the gap is at [parent * 2] */
93  uint child = gap * 2;
94 
95  /* while children are valid */
96  while (child <= this->items) {
97  /* choose the smaller child */
98  if (child < this->items && *this->data[child + 1] < *this->data[child]) {
99  child++;
100  }
101  /* is it smaller than our parent? */
102  if (!(*this->data[child] < *item)) {
103  /* the smaller child is still bigger or same as parent => we are done */
104  break;
105  }
106  /* if smaller child is smaller than parent, it will become new parent */
107  this->data[gap] = this->data[child];
108  gap = child;
109  /* where do we have our new children? */
110  child = gap * 2;
111  }
112  return gap;
113  }
114 
124  inline uint HeapifyUp(uint gap, T *item)
125  {
126  assert(gap != 0);
127 
128  uint parent;
129 
130  while (gap > 1) {
131  /* compare [gap] with its parent */
132  parent = gap / 2;
133  if (!(*item < *this->data[parent])) {
134  /* we don't need to continue upstairs */
135  break;
136  }
137  this->data[gap] = this->data[parent];
138  gap = parent;
139  }
140  return gap;
141  }
142 
143 #if BINARYHEAP_CHECK
144 
145  inline void CheckConsistency()
146  {
147  for (uint child = 2; child <= this->items; child++) {
148  uint parent = child / 2;
149  assert(!(*this->data[child] < *this->data[parent]));
150  }
151  }
152 #endif
153 
154 public:
160  inline uint Length() const { return this->items; }
161 
167  inline bool IsEmpty() const { return this->items == 0; }
168 
174  inline bool IsFull() const { return this->items >= this->capacity; }
175 
181  inline T *Begin()
182  {
183  assert(!this->IsEmpty());
184  return this->data[1];
185  }
186 
194  inline T *End()
195  {
196  return this->data[1 + this->items];
197  }
198 
204  inline void Include(T *new_item)
205  {
206  if (this->IsFull()) {
207  assert(this->capacity < UINT_MAX / 2);
208 
209  this->capacity *= 2;
210  this->data = ReallocT<T*>(this->data, this->capacity + 1);
211  }
212 
213  /* Make place for new item. A gap is now at the end of the tree. */
214  uint gap = this->HeapifyUp(++items, new_item);
215  this->data[gap] = new_item;
216  CHECK_CONSISTY();
217  }
218 
225  inline T *Shift()
226  {
227  assert(!this->IsEmpty());
228 
229  T *first = this->Begin();
230 
231  this->items--;
232  /* at index 1 we have a gap now */
233  T *last = this->End();
234  uint gap = this->HeapifyDown(1, last);
235  /* move last item to the proper place */
236  if (!this->IsEmpty()) this->data[gap] = last;
237 
238  CHECK_CONSISTY();
239  return first;
240  }
241 
247  inline void Remove(uint index)
248  {
249  if (index < this->items) {
250  assert(index != 0);
251  this->items--;
252  /* at position index we have a gap now */
253 
254  T *last = this->End();
255  /* Fix binary tree up and downwards */
256  uint gap = this->HeapifyUp(index, last);
257  gap = this->HeapifyDown(gap, last);
258  /* move last item to the proper place */
259  if (!this->IsEmpty()) this->data[gap] = last;
260  } else {
261  assert(index == this->items);
262  this->items--;
263  }
264  CHECK_CONSISTY();
265  }
266 
275  inline uint FindIndex(const T &item) const
276  {
277  if (this->IsEmpty()) return 0;
278  for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) {
279  if (*ppI == &item) {
280  return ppI - this->data;
281  }
282  }
283  return 0;
284  }
285 
290  inline void Clear() { this->items = 0; }
291 };
292 
293 #endif /* BINARYHEAP_HPP */