aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
heap_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief template implementations of heaps
25  *
26  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 #include <sstream>
29 #include <string>
30 
31 // to ease IDE parser
32 #include <agrum/tools/core/heap.h>
33 
34 namespace gum {
35 
36  // basic constructor. Creates an empty heap
37  template < typename Val, typename Cmp, typename Alloc >
38  Heap< Val, Cmp, Alloc >::Heap(Cmp compare, Size capacity) : cmp__(compare) {
39  heap__.reserve(capacity);
40 
41  // for debugging purposes
42  GUM_CONSTRUCTOR(Heap);
43  }
44 
45  // initializer list constructor
46  template < typename Val, typename Cmp, typename Alloc >
47  Heap< Val, Cmp, Alloc >::Heap(std::initializer_list< Val > list) {
48  heap__.reserve(list.size());
49  for (const auto& elt: list) {
50  insert(elt);
51  }
52 
53  // for debugging purposes
54  GUM_CONSTRUCTOR(Heap);
55  }
56 
57  // copy constructor
58  template < typename Val, typename Cmp, typename Alloc >
59  Heap< Val, Cmp, Alloc >::Heap(const Heap< Val, Cmp, Alloc >& from) :
60  heap__(from.heap__), nb_elements__(from.nb_elements__), cmp__(from.cmp__) {
61  // for debugging purposes
62  GUM_CONS_CPY(Heap);
63  }
64 
65  // generalized copy constructor
66  template < typename Val, typename Cmp, typename Alloc >
67  template < typename OtherAlloc >
68  Heap< Val, Cmp, Alloc >::Heap(const Heap< Val, Cmp, OtherAlloc >& from) :
69  nb_elements__(from.nb_elements__), cmp__(from.cmp__) {
70  heap__.reserve(nb_elements__);
71 
72  // copy the elements of from.heap__
73  for (unsigned i = 0; i < nb_elements__; ++i)
74  heap__.push_back(from.heap__[i]);
75 
76  // for debugging purposes
77  GUM_CONS_CPY(Heap);
78  }
79 
80  // move constructor
81  template < typename Val, typename Cmp, typename Alloc >
82  Heap< Val, Cmp, Alloc >::Heap(Heap< Val, Cmp, Alloc >&& from) noexcept :
83  heap__(std::move(from.heap__)), nb_elements__(std::move(from.nb_elements__)),
84  cmp__(std::move(from.cmp__)) {
85  // for debugging purposes
86  GUM_CONS_MOV(Heap);
87  }
88 
89  // destructor
90  template < typename Val, typename Cmp, typename Alloc >
91  Heap< Val, Cmp, Alloc >::~Heap() {
92  // for debugging purposes
93  GUM_DESTRUCTOR(Heap);
94  }
95 
96  // copy operator
97  template < typename Val, typename Cmp, typename Alloc >
98  Heap< Val, Cmp, Alloc >&
99  Heap< Val, Cmp, Alloc >::operator=(const Heap< Val, Cmp, Alloc >& from) {
100  // avoid self assignment
101  if (this != &from) {
102  try {
103  heap__ = from.heap__;
104  } catch (...) {
105  heap__.clear();
106  nb_elements__ = 0;
107 
108  throw;
109  }
110 
111  // set the comparison function
112  cmp__ = from.cmp__;
113  nb_elements__ = from.nb_elements__;
114 
115  // for debugging purposes
116  GUM_OP_CPY(Heap);
117  }
118 
119  return *this;
120  }
121 
122  // generalized copy operator
123  template < typename Val, typename Cmp, typename Alloc >
124  template < typename OtherAlloc >
125  Heap< Val, Cmp, Alloc >&
126  Heap< Val, Cmp, Alloc >::operator=(const Heap< Val, Cmp, OtherAlloc >& from) {
127  // avoid self assignment
128  if (this != &from) {
129  try {
130  heap__.clear();
131 
132  if (heap__.capacity() < from.nb_elements__)
133  heap__.reserve(from.nb_elements__);
134 
135  for (unsigned int i = 0; i < from.nb_elements__; ++i) {
136  heap__.push_back(from.heap__[i]);
137  }
138  } catch (...) {
139  heap__.clear();
140  nb_elements__ = 0;
141  throw;
142  }
143 
144  cmp__ = from.cmp__;
145  nb_elements__ = from.nb_elements__;
146 
147  // for debugging purposes
148  GUM_OP_CPY(Heap);
149  }
150 
151  return *this;
152  }
153 
154  // move operator
155  template < typename Val, typename Cmp, typename Alloc >
156  Heap< Val, Cmp, Alloc >&
157  Heap< Val, Cmp, Alloc >::operator=(Heap< Val, Cmp, Alloc >&& from) noexcept {
158  // avoid self assignment
159  if (this != &from) {
160  heap__ = std::move(from.heap__);
161  nb_elements__ = std::move(from.nb_elements__);
162  cmp__ = std::move(from.cmp__);
163  }
164 
165  return *this;
166  }
167 
168  // returns the element at the top of the heap
169  template < typename Val, typename Cmp, typename Alloc >
170  INLINE const Val& Heap< Val, Cmp, Alloc >::top() const {
171  if (!nb_elements__) { GUM_ERROR(NotFound, "empty heap"); }
172 
173  return heap__[0];
174  }
175 
176  // returns the number of elements in the heap
177  template < typename Val, typename Cmp, typename Alloc >
178  INLINE Size Heap< Val, Cmp, Alloc >::size() const noexcept {
179  return nb_elements__;
180  }
181 
182  // return the size of the array storing the heap
183  template < typename Val, typename Cmp, typename Alloc >
184  INLINE Size Heap< Val, Cmp, Alloc >::capacity() const noexcept {
185  return Size(heap__.size());
186  }
187 
188  // changes the size of the array storing the heap
189  template < typename Val, typename Cmp, typename Alloc >
190  INLINE void Heap< Val, Cmp, Alloc >::resize(Size new_size) {
191  if (new_size > nb_elements__) heap__.reserve(new_size);
192  }
193 
194  // removes the element at position 'index' from the heap
195  template < typename Val, typename Cmp, typename Alloc >
196  void Heap< Val, Cmp, Alloc >::eraseByPos(Size index) {
197  if (index >= nb_elements__) return;
198 
199  // remove the element and put the last element in its place
200  Val last = std::move(heap__[nb_elements__ - 1]);
201  heap__.pop_back();
202  --nb_elements__;
203 
204  if (!nb_elements__ || (index == nb_elements__)) return;
205 
206  // restore the heap property
207  Size i = index;
208 
209  for (Size j = (index << 1) + 1; j < nb_elements__; i = j, j = (j << 1) + 1) {
210  // let j be the max child
211  if ((j + 1 < nb_elements__) && cmp__(heap__[j + 1], heap__[j])) ++j;
212 
213  // if "last" is smaller than heap__[j], "last" must be stored at index i
214  if (cmp__(last, heap__[j])) break;
215 
216  heap__[i] = std::move(heap__[j]);
217  }
218 
219  heap__[i] = std::move(last);
220  }
221 
222  // removes a given element from the heap (but does not return it)
223  template < typename Val, typename Cmp, typename Alloc >
224  INLINE void Heap< Val, Cmp, Alloc >::erase(const Val& val) {
225  // find val in the heap
226  for (Size i = 0; i < nb_elements__; ++i)
227  if (heap__[i] == val) {
228  eraseByPos(i);
229  break;
230  }
231  }
232 
233  // removes the top of the heap (but does not return it)
234  template < typename Val, typename Cmp, typename Alloc >
235  INLINE void Heap< Val, Cmp, Alloc >::eraseTop() {
236  // if the heap is empty, do nothing
237  if (!nb_elements__) return;
238  eraseByPos(0);
239  }
240 
241  // removes the top element from the heap and return it
242  template < typename Val, typename Cmp, typename Alloc >
243  INLINE Val Heap< Val, Cmp, Alloc >::pop() {
244  if (!nb_elements__) { GUM_ERROR(NotFound, "empty heap"); }
245 
246  Val v = heap__[0];
247  eraseByPos(0);
248  return v;
249  }
250 
251  // after inserting an element at the end of the heap, restore heap property
252  template < typename Val, typename Cmp, typename Alloc >
253  Size Heap< Val, Cmp, Alloc >::restoreHeap__() {
254  // get the element at the end of the heap
255  Size i = nb_elements__ - 1;
256  Val v = std::move(heap__[i]);
257 
258  // restore the heap property
259  for (Size j = (i - 1) >> 1; i && cmp__(v, heap__[j]); i = j, j = (j - 1) >> 1)
260  heap__[i] = std::move(heap__[j]);
261 
262  heap__[i] = std::move(v);
263 
264  return i;
265  }
266 
267  // inserts a new (a copy) element in the heap
268  template < typename Val, typename Cmp, typename Alloc >
269  INLINE Size Heap< Val, Cmp, Alloc >::insert(const Val& val) {
270  // create a new element at the end of the heap
271  heap__.push_back(val);
272  ++nb_elements__;
273  return restoreHeap__();
274  }
275 
276  // inserts a new (a copy) element in the heap
277  template < typename Val, typename Cmp, typename Alloc >
278  Size Heap< Val, Cmp, Alloc >::insert(Val&& val) {
279  // create a new element at the end of the heap
280  heap__.push_back(std::move(val));
281  ++nb_elements__;
282  return restoreHeap__();
283  }
284 
285  // emplace a new element in the heap
286  template < typename Val, typename Cmp, typename Alloc >
287  template < typename... Args >
288  Size Heap< Val, Cmp, Alloc >::emplace(Args&&... args) {
289  // create a new element at the end of the heap
290  heap__.emplace_back(std::forward< Args >(args)...);
291  ++nb_elements__;
292  return restoreHeap__();
293  }
294 
295  // indicates whether the heap is empty
296  template < typename Val, typename Cmp, typename Alloc >
297  INLINE bool Heap< Val, Cmp, Alloc >::empty() const noexcept {
298  return (nb_elements__ == 0);
299  }
300 
301  // indicates whether the heap contains a given value
302  template < typename Val, typename Cmp, typename Alloc >
303  INLINE bool Heap< Val, Cmp, Alloc >::contains(const Val& val) const {
304  for (Size i = 0; i < nb_elements__; ++i)
305  if (heap__[i] == val) return true;
306 
307  return false;
308  }
309 
310  // returns the element at index elt from the heap
311  template < typename Val, typename Cmp, typename Alloc >
312  INLINE const Val& Heap< Val, Cmp, Alloc >::operator[](Size index) const {
313  // check if the element exists
314  if (index >= nb_elements__) {
315  GUM_ERROR(NotFound, "not enough elements in the heap");
316  }
317 
318  return heap__[index];
319  }
320 
321  // displays the content of the heap
322  template < typename Val, typename Cmp, typename Alloc >
323  std::string Heap< Val, Cmp, Alloc >::toString() const {
324  bool deja = false;
325  std::stringstream stream;
326  stream << "[";
327 
328  for (Size i = 0; i != nb_elements__; ++i, deja = true) {
329  if (deja) stream << " , ";
330 
331  stream << heap__[i];
332  }
333 
334  stream << "]";
335 
336  return stream.str();
337  }
338 
339  // A \c << operator for Heap
340  template < typename Val, typename Cmp, typename Alloc >
341  INLINE std::ostream& operator<<(std::ostream& stream,
342  const Heap< Val, Cmp, Alloc >& heap) {
343  stream << heap.toString();
344  return stream;
345  }
346 
347 } /* namespace gum */