OpenTTD Source  20240919-master-gdf0233f4c2
binaryheap.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #ifndef BINARYHEAP_HPP
11 #define BINARYHEAP_HPP
12 
14 #define BINARYHEAP_CHECK 0
15 
16 #if BINARYHEAP_CHECK
17 
18 # define CHECK_CONSISTY() this->CheckConsistency()
19 #else
20 
21 # define CHECK_CONSISTY() ;
22 #endif
23 
52 template <class T>
53 class CBinaryHeapT {
54 private:
55  size_t items = 0;
56  std::vector<T *> data;
57 
58 public:
63  explicit CBinaryHeapT(size_t initial_capacity)
64  {
65  this->data.reserve(initial_capacity);
66  this->Clear();
67  }
68 
69 protected:
79  inline size_t HeapifyDown(size_t gap, T *item)
80  {
81  assert(gap != 0);
82 
83  /* The first child of the gap is at [parent * 2] */
84  size_t child = gap * 2;
85 
86  /* while children are valid */
87  while (child <= this->items) {
88  /* choose the smaller child */
89  if (child < this->items && *this->data[child + 1] < *this->data[child]) {
90  child++;
91  }
92  /* is it smaller than our parent? */
93  if (!(*this->data[child] < *item)) {
94  /* the smaller child is still bigger or same as parent => we are done */
95  break;
96  }
97  /* if smaller child is smaller than parent, it will become new parent */
98  this->data[gap] = this->data[child];
99  gap = child;
100  /* where do we have our new children? */
101  child = gap * 2;
102  }
103  return gap;
104  }
105 
115  inline size_t HeapifyUp(size_t gap, T *item)
116  {
117  assert(gap != 0);
118 
119  size_t parent;
120 
121  while (gap > 1) {
122  /* compare [gap] with its parent */
123  parent = gap / 2;
124  if (!(*item < *this->data[parent])) {
125  /* we don't need to continue upstairs */
126  break;
127  }
128  this->data[gap] = this->data[parent];
129  gap = parent;
130  }
131  return gap;
132  }
133 
134 #if BINARYHEAP_CHECK
135 
136  inline void CheckConsistency()
137  {
138  assert(this->items == this->data.size() - 1);
139  for (size_t child = 2; child <= this->items; child++) {
140  size_t parent = child / 2;
141  assert(!(*this->data[child] < *this->data[parent]));
142  }
143  }
144 #endif
145 
146 public:
152  inline size_t Length() const
153  {
154  return this->items;
155  }
156 
162  inline bool IsEmpty() const
163  {
164  return this->items == 0;
165  }
166 
172  inline T *Begin()
173  {
174  assert(!this->IsEmpty());
175  return this->data[1];
176  }
177 
185  inline T *End()
186  {
187  return this->data[1 + this->items];
188  }
189 
195  inline void Include(T *new_item)
196  {
197  /* Make place for new item. A gap is now at the end of the tree. */
198  this->data.emplace_back();
199  size_t gap = this->HeapifyUp(++items, new_item);
200  this->data[gap] = new_item;
201  CHECK_CONSISTY();
202  }
203 
210  inline T *Shift()
211  {
212  assert(!this->IsEmpty());
213 
214  T *first = this->Begin();
215 
216  this->items--;
217  /* at index 1 we have a gap now */
218  T *last = this->End();
219  size_t gap = this->HeapifyDown(1, last);
220  /* move last item to the proper place */
221  if (!this->IsEmpty()) this->data[gap] = last;
222  this->data.pop_back();
223 
224  CHECK_CONSISTY();
225  return first;
226  }
227 
233  inline void Remove(size_t index)
234  {
235  if (index < this->items) {
236  assert(index != 0);
237  this->items--;
238  /* at position index we have a gap now */
239 
240  T *last = this->End();
241  /* Fix binary tree up and downwards */
242  size_t gap = this->HeapifyUp(index, last);
243  gap = this->HeapifyDown(gap, last);
244  /* move last item to the proper place */
245  if (!this->IsEmpty()) this->data[gap] = last;
246  } else {
247  assert(index == this->items);
248  this->items--;
249  }
250  this->data.pop_back();
251 
252  CHECK_CONSISTY();
253  }
254 
263  inline size_t FindIndex(const T &item) const
264  {
265  auto it = std::find(this->data.begin(), this->data.end(), &item);
266  return it == this->data.end() ? 0 : std::distance(this->data.begin(), it);
267  }
268 
273  inline void Clear()
274  {
275  this->items = 0;
276  this->data.resize(1);
277 
278  CHECK_CONSISTY();
279  }
280 };
281 
282 #endif /* BINARYHEAP_HPP */
CHECK_CONSISTY
#define CHECK_CONSISTY()
Don't check for consistency.
Definition: binaryheap.hpp:21
CBinaryHeapT::Shift
T * Shift()
Remove and return the smallest (and also first) item from the priority queue.
Definition: binaryheap.hpp:210
CBinaryHeapT::HeapifyDown
size_t HeapifyDown(size_t gap, T *item)
Get position for fixing a gap (downwards).
Definition: binaryheap.hpp:79
CBinaryHeapT::items
size_t items
Number of valid items in the heap.
Definition: binaryheap.hpp:55
CBinaryHeapT::IsEmpty
bool IsEmpty() const
Test if the priority queue is empty.
Definition: binaryheap.hpp:162
CBinaryHeapT
Binary Heap as C++ template.
Definition: binaryheap.hpp:53
CBinaryHeapT::CBinaryHeapT
CBinaryHeapT(size_t initial_capacity)
Create a binary heap.
Definition: binaryheap.hpp:63
CBinaryHeapT::Clear
void Clear()
Make the priority queue empty.
Definition: binaryheap.hpp:273
CBinaryHeapT::FindIndex
size_t FindIndex(const T &item) const
Search for an item in the priority queue.
Definition: binaryheap.hpp:263
CBinaryHeapT::Remove
void Remove(size_t index)
Remove item at given index from the priority queue.
Definition: binaryheap.hpp:233
CBinaryHeapT::HeapifyUp
size_t HeapifyUp(size_t gap, T *item)
Get position for fixing a gap (upwards).
Definition: binaryheap.hpp:115
CBinaryHeapT::data
std::vector< T * > data
The pointer to the heap item pointers.
Definition: binaryheap.hpp:56
CBinaryHeapT::Length
size_t Length() const
Get the number of items stored in the priority queue.
Definition: binaryheap.hpp:152
CBinaryHeapT::Include
void Include(T *new_item)
Insert new item into the priority queue, maintaining heap order.
Definition: binaryheap.hpp:195
CBinaryHeapT::End
T * End()
Get the LAST item in the binary tree.
Definition: binaryheap.hpp:185
CBinaryHeapT::Begin
T * Begin()
Get the smallest item in the binary tree.
Definition: binaryheap.hpp:172