OpenTTD
binaryheap.hpp
Go to the documentation of this file.
1 /* $Id: binaryheap.hpp 27363 2015-08-08 13:19:38Z alberth $ */
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
161  {
162  return this->items;
163  }
164 
170  inline bool IsEmpty() const
171  {
172  return this->items == 0;
173  }
174 
180  inline bool IsFull() const
181  {
182  return this->items >= this->capacity;
183  }
184 
190  inline T *Begin()
191  {
192  assert(!this->IsEmpty());
193  return this->data[1];
194  }
195 
203  inline T *End()
204  {
205  return this->data[1 + this->items];
206  }
207 
213  inline void Include(T *new_item)
214  {
215  if (this->IsFull()) {
216  assert(this->capacity < UINT_MAX / 2);
217 
218  this->capacity *= 2;
219  this->data = ReallocT<T*>(this->data, this->capacity + 1);
220  }
221 
222  /* Make place for new item. A gap is now at the end of the tree. */
223  uint gap = this->HeapifyUp(++items, new_item);
224  this->data[gap] = new_item;
225  CHECK_CONSISTY();
226  }
227 
234  inline T *Shift()
235  {
236  assert(!this->IsEmpty());
237 
238  T *first = this->Begin();
239 
240  this->items--;
241  /* at index 1 we have a gap now */
242  T *last = this->End();
243  uint gap = this->HeapifyDown(1, last);
244  /* move last item to the proper place */
245  if (!this->IsEmpty()) this->data[gap] = last;
246 
247  CHECK_CONSISTY();
248  return first;
249  }
250 
256  inline void Remove(uint index)
257  {
258  if (index < this->items) {
259  assert(index != 0);
260  this->items--;
261  /* at position index we have a gap now */
262 
263  T *last = this->End();
264  /* Fix binary tree up and downwards */
265  uint gap = this->HeapifyUp(index, last);
266  gap = this->HeapifyDown(gap, last);
267  /* move last item to the proper place */
268  if (!this->IsEmpty()) this->data[gap] = last;
269  } else {
270  assert(index == this->items);
271  this->items--;
272  }
273  CHECK_CONSISTY();
274  }
275 
284  inline uint FindIndex(const T &item) const
285  {
286  if (this->IsEmpty()) return 0;
287  for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) {
288  if (*ppI == &item) {
289  return ppI - this->data;
290  }
291  }
292  return 0;
293  }
294 
299  inline void Clear()
300  {
301  this->items = 0;
302  }
303 };
304 
305 #endif /* BINARYHEAP_HPP */