aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
heap_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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  GUM_CONSTRUCTOR(Heap);
42  }
43 
44  // initializer list constructor
45  template < typename Val, typename Cmp, typename Alloc >
46  Heap< Val, Cmp, Alloc >::Heap(std::initializer_list< Val > list) {
47  _heap_.reserve(list.size());
48  for (const auto& elt: list) {
49  insert(elt);
50  }
51 
52  GUM_CONSTRUCTOR(Heap);
53  }
54 
55  // copy constructor
56  template < typename Val, typename Cmp, typename Alloc >
57  Heap< Val, Cmp, Alloc >::Heap(const Heap< Val, Cmp, Alloc >& from) :
58  _heap_(from._heap_), _nb_elements_(from._nb_elements_), _cmp_(from._cmp_) {
59  // for debugging purposes
60  GUM_CONS_CPY(Heap);
61  }
62 
63  // generalized copy constructor
64  template < typename Val, typename Cmp, typename Alloc >
65  template < typename OtherAlloc >
66  Heap< Val, Cmp, Alloc >::Heap(const Heap< Val, Cmp, OtherAlloc >& from) :
67  _nb_elements_(from._nb_elements_), _cmp_(from._cmp_) {
68  _heap_.reserve(_nb_elements_);
69 
70  // copy the elements of from. _heap_
71  for (unsigned i = 0; i < _nb_elements_; ++i)
72  _heap_.push_back(from._heap_[i]);
73 
74  // for debugging purposes
75  GUM_CONS_CPY(Heap);
76  }
77 
78  // move constructor
79  template < typename Val, typename Cmp, typename Alloc >
80  Heap< Val, Cmp, Alloc >::Heap(Heap< Val, Cmp, Alloc >&& from) noexcept :
81  _heap_(std::move(from._heap_)), _nb_elements_(std::move(from._nb_elements_)),
82  _cmp_(std::move(from._cmp_)) {
83  // for debugging purposes
84  GUM_CONS_MOV(Heap);
85  }
86 
87  // destructor
88  template < typename Val, typename Cmp, typename Alloc >
89  Heap< Val, Cmp, Alloc >::~Heap() {
90  // for debugging purposes
91  GUM_DESTRUCTOR(Heap);
92  }
93 
94  // copy operator
95  template < typename Val, typename Cmp, typename Alloc >
96  Heap< Val, Cmp, Alloc >& Heap< Val, Cmp, Alloc >::operator=(const Heap< Val, Cmp, Alloc >& from) {
97  // avoid self assignment
98  if (this != &from) {
99  try {
100  _heap_ = from._heap_;
101  } catch (...) {
102  _heap_.clear();
103  _nb_elements_ = 0;
104 
105  throw;
106  }
107 
108  // set the comparison function
109  _cmp_ = from._cmp_;
110  _nb_elements_ = from._nb_elements_;
111 
112  // for debugging purposes
113  GUM_OP_CPY(Heap);
114  }
115 
116  return *this;
117  }
118 
119  // generalized copy operator
120  template < typename Val, typename Cmp, typename Alloc >
121  template < typename OtherAlloc >
122  Heap< Val, Cmp, Alloc >&
123  Heap< Val, Cmp, Alloc >::operator=(const Heap< Val, Cmp, OtherAlloc >& from) {
124  // avoid self assignment
125  if (this != &from) {
126  try {
127  _heap_.clear();
128 
129  if (_heap_.capacity() < from._nb_elements_) _heap_.reserve(from._nb_elements_);
130 
131  for (unsigned int i = 0; i < from._nb_elements_; ++i) {
132  _heap_.push_back(from._heap_[i]);
133  }
134  } catch (...) {
135  _heap_.clear();
136  _nb_elements_ = 0;
137  throw;
138  }
139 
140  _cmp_ = from._cmp_;
141  _nb_elements_ = from._nb_elements_;
142 
143  // for debugging purposes
144  GUM_OP_CPY(Heap);
145  }
146 
147  return *this;
148  }
149 
150  // move operator
151  template < typename Val, typename Cmp, typename Alloc >
152  Heap< Val, Cmp, Alloc >&
153  Heap< Val, Cmp, Alloc >::operator=(Heap< Val, Cmp, Alloc >&& from) noexcept {
154  // avoid self assignment
155  if (this != &from) {
156  _heap_ = std::move(from._heap_);
157  _nb_elements_ = std::move(from._nb_elements_);
158  _cmp_ = std::move(from._cmp_);
159  }
160 
161  return *this;
162  }
163 
164  // returns the element at the top of the heap
165  template < typename Val, typename Cmp, typename Alloc >
166  INLINE const Val& Heap< Val, Cmp, Alloc >::top() const {
167  if (!_nb_elements_) { GUM_ERROR(NotFound, "empty heap") }
168 
169  return _heap_[0];
170  }
171 
172  // returns the number of elements in the heap
173  template < typename Val, typename Cmp, typename Alloc >
174  INLINE Size Heap< Val, Cmp, Alloc >::size() const noexcept {
175  return _nb_elements_;
176  }
177 
178  // return the size of the array storing the heap
179  template < typename Val, typename Cmp, typename Alloc >
180  INLINE Size Heap< Val, Cmp, Alloc >::capacity() const noexcept {
181  return Size(_heap_.size());
182  }
183 
184  // changes the size of the array storing the heap
185  template < typename Val, typename Cmp, typename Alloc >
186  INLINE void Heap< Val, Cmp, Alloc >::resize(Size new_size) {
187  if (new_size > _nb_elements_) _heap_.reserve(new_size);
188  }
189 
190  // removes the element at position 'index' from the heap
191  template < typename Val, typename Cmp, typename Alloc >
192  void Heap< Val, Cmp, Alloc >::eraseByPos(Size index) {
193  if (index >= _nb_elements_) return;
194 
195  // remove the element and put the last element in its place
196  Val last = std::move(_heap_[_nb_elements_ - 1]);
197  _heap_.pop_back();
198  --_nb_elements_;
199 
200  if (!_nb_elements_ || (index == _nb_elements_)) return;
201 
202  // restore the heap property
203  Size i = index;
204 
205  for (Size j = (index << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
206  // let j be the max child
207  if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1], _heap_[j])) ++j;
208 
209  // if "last" is smaller than _heap_[j], "last" must be stored at index i
210  if (_cmp_(last, _heap_[j])) break;
211 
212  _heap_[i] = std::move(_heap_[j]);
213  }
214 
215  _heap_[i] = std::move(last);
216  }
217 
218  // removes a given element from the heap (but does not return it)
219  template < typename Val, typename Cmp, typename Alloc >
220  INLINE void Heap< Val, Cmp, Alloc >::erase(const Val& val) {
221  // find val in the heap
222  for (Size i = 0; i < _nb_elements_; ++i)
223  if (_heap_[i] == val) {
224  eraseByPos(i);
225  break;
226  }
227  }
228 
229  // removes the top of the heap (but does not return it)
230  template < typename Val, typename Cmp, typename Alloc >
231  INLINE void Heap< Val, Cmp, Alloc >::eraseTop() {
232  // if the heap is empty, do nothing
233  if (!_nb_elements_) return;
234  eraseByPos(0);
235  }
236 
237  // removes the top element from the heap and return it
238  template < typename Val, typename Cmp, typename Alloc >
239  INLINE Val Heap< Val, Cmp, Alloc >::pop() {
240  if (!_nb_elements_) { GUM_ERROR(NotFound, "empty heap") }
241 
242  Val v = _heap_[0];
243  eraseByPos(0);
244  return v;
245  }
246 
247  // after inserting an element at the end of the heap, restore heap property
248  template < typename Val, typename Cmp, typename Alloc >
249  Size Heap< Val, Cmp, Alloc >::_restoreHeap_() {
250  // get the element at the end of the heap
251  Size i = _nb_elements_ - 1;
252  Val v = std::move(_heap_[i]);
253 
254  // restore the heap property
255  for (Size j = (i - 1) >> 1; i && _cmp_(v, _heap_[j]); i = j, j = (j - 1) >> 1)
256  _heap_[i] = std::move(_heap_[j]);
257 
258  _heap_[i] = std::move(v);
259 
260  return i;
261  }
262 
263  // inserts a new (a copy) element in the heap
264  template < typename Val, typename Cmp, typename Alloc >
265  INLINE Size Heap< Val, Cmp, Alloc >::insert(const Val& val) {
266  // create a new element at the end of the heap
267  _heap_.push_back(val);
268  ++_nb_elements_;
269  return _restoreHeap_();
270  }
271 
272  // inserts a new (a copy) element in the heap
273  template < typename Val, typename Cmp, typename Alloc >
274  Size Heap< Val, Cmp, Alloc >::insert(Val&& val) {
275  // create a new element at the end of the heap
276  _heap_.push_back(std::move(val));
277  ++_nb_elements_;
278  return _restoreHeap_();
279  }
280 
281  // emplace a new element in the heap
282  template < typename Val, typename Cmp, typename Alloc >
283  template < typename... Args >
284  Size Heap< Val, Cmp, Alloc >::emplace(Args&&... args) {
285  // create a new element at the end of the heap
286  _heap_.emplace_back(std::forward< Args >(args)...);
287  ++_nb_elements_;
288  return _restoreHeap_();
289  }
290 
291  // indicates whether the heap is empty
292  template < typename Val, typename Cmp, typename Alloc >
293  INLINE bool Heap< Val, Cmp, Alloc >::empty() const noexcept {
294  return (_nb_elements_ == 0);
295  }
296 
297  // indicates whether the heap contains a given value
298  template < typename Val, typename Cmp, typename Alloc >
299  INLINE bool Heap< Val, Cmp, Alloc >::contains(const Val& val) const {
300  for (Size i = 0; i < _nb_elements_; ++i)
301  if (_heap_[i] == val) return true;
302 
303  return false;
304  }
305 
306  // returns the element at index elt from the heap
307  template < typename Val, typename Cmp, typename Alloc >
308  INLINE const Val& Heap< Val, Cmp, Alloc >::operator[](Size index) const {
309  // check if the element exists
310  if (index >= _nb_elements_) { GUM_ERROR(NotFound, "not enough elements in the heap") }
311 
312  return _heap_[index];
313  }
314 
315  // displays the content of the heap
316  template < typename Val, typename Cmp, typename Alloc >
317  std::string Heap< Val, Cmp, Alloc >::toString() const {
318  bool deja = false;
319  std::stringstream stream;
320  stream << "[";
321 
322  for (Size i = 0; i != _nb_elements_; ++i, deja = true) {
323  if (deja) stream << " , ";
324 
325  stream << _heap_[i];
326  }
327 
328  stream << "]";
329 
330  return stream.str();
331  }
332 
333  // A \c << operator for Heap
334  template < typename Val, typename Cmp, typename Alloc >
335  INLINE std::ostream& operator<<(std::ostream& stream, const Heap< Val, Cmp, Alloc >& heap) {
336  stream << heap.toString();
337  return stream;
338  }
339 
340 } /* namespace gum */