aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
priorityQueue_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
49
51
52namespace gum {
53
54 // ===========================================================================
55 // === GENERAL IMPLEMENTATIION OF PRIORITY QUEUES ===
56 // ===========================================================================
57
58 // basic constructor
59 template < typename Val, typename Priority, typename Cmp, bool Gen >
67
68 // initializer list constructor
69 template < typename Val, typename Priority, typename Cmp, bool Gen >
71 std::initializer_list< std::pair< Val, Priority > > list) :
72 _indices_(Size(list.size()) / 2, true, true) {
73 // fill the queue
74 _heap_.reserve(list.size());
75 for (const auto& elt: list) {
76 insert(elt.first, elt.second);
77 }
78
79 GUM_CONSTRUCTOR(PriorityQueueImplementation);
80 }
81
82 // copy constructor
83 template < typename Val, typename Priority, typename Cmp, bool Gen >
87 _cmp_(from._cmp_) {
88 // fill the heap structure
89 for (const auto& elt: _indices_) {
90 _heap_[elt.second].second = &(elt.first);
91 }
92
93 GUM_CONS_CPY(PriorityQueueImplementation);
94 }
95
96 // move constructor
97 template < typename Val, typename Priority, typename Cmp, bool Gen >
104
105 // destructor
106 template < typename Val, typename Priority, typename Cmp, bool Gen >
110
111 // copy operator
112 template < typename Val, typename Priority, typename Cmp, bool Gen >
116 // avoid self assignment
117 if (this != &from) {
119
120 try {
121 // set the comparison function
122 _cmp_ = from._cmp_;
123
124 // copy the indices and the heap
125 _indices_ = from._indices_;
126 _heap_ = from._heap_;
128
129 // restore the link between _indices_ and _heap_
130 for (const auto& elt: _indices_) {
131 _heap_[elt.second].second = &(elt.first);
132 }
133 } catch (...) {
134 _heap_.clear();
135 _indices_.clear();
136 _nb_elements_ = 0;
137
138 throw;
139 }
140 }
141
142 return *this;
143 }
144
145 // move operator
146 template < typename Val, typename Priority, typename Cmp, bool Gen >
150 // avoid self assignment
151 if (this != &from) {
153
154 _indices_ = std::move(from._indices_);
155 _heap_ = std::move(from._heap_);
156 _cmp_ = std::move(from._cmp_);
157 _nb_elements_ = std::move(from._nb_elements_);
158 }
159
160 return *this;
161 }
162
163 // returns the element at the top of the priority queue
164 template < typename Val, typename Priority, typename Cmp, bool Gen >
166 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
167
168 return *(_heap_[0].second);
169 }
170
171 // returns the priority of the top element
172 template < typename Val, typename Priority, typename Cmp, bool Gen >
173 INLINE const Priority&
175 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
176
177 return _heap_[0].first;
178 }
180 // returns the number of elements in the priority queue
181 template < typename Val, typename Priority, typename Cmp, bool Gen >
185
186 // return the size of the array storing the priority queue
187 template < typename Val, typename Priority, typename Cmp, bool Gen >
189 return Size(_heap_.capacity());
190 }
191
192 // changes the size of the array storing the priority queue
193 template < typename Val, typename Priority, typename Cmp, bool Gen >
195 if (new_size < _nb_elements_) return;
196
197 _heap_.reserve(new_size);
198 _indices_.resize(new_size / 2);
199 }
200
201 // removes all the elements from the queue
202 template < typename Val, typename Priority, typename Cmp, bool Gen >
204 _nb_elements_ = 0;
205 _heap_.clear();
206 _indices_.clear();
207 }
208
209 // removes the element at index elt from the priority queue
210 template < typename Val, typename Priority, typename Cmp, bool Gen >
212 if (index >= _nb_elements_) return;
213
214 // remove the element from the hashtable
215 _indices_.erase(*(_heap_[index].second));
216
217 // put the last element at the "index" location
218 std::pair< Priority, const Val* > last = std::move(_heap_[_nb_elements_ - 1]);
219 _heap_.pop_back();
221
222 if (!_nb_elements_ || (index == _nb_elements_)) return;
223
224 // restore the heap property
225 Size i = index;
227 for (Size j = (index << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
228 // let j be the max child
229 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
230
231 // if "last" is lower than heap[j], "last" must be stored at index i
232 if (_cmp_(last.first, _heap_[j].first)) break;
234 // else pull up the jth node
235 _heap_[i] = std::move(_heap_[j]);
236 _indices_[*(_heap_[i].second)] = i;
237 }
238
239 // put "last" back into the heap
240 _heap_[i] = std::move(last);
241 _indices_[*(_heap_[i].second)] = i;
242 }
243
244 // removes a given element from the priority queue (but does not return it)
245 template < typename Val, typename Priority, typename Cmp, bool Gen >
247 try {
248 eraseByPos(_indices_[val]);
249 } catch (NotFound const&) {}
250 }
251
252 // removes the top of the priority queue (but does not return it)
253 template < typename Val, typename Priority, typename Cmp, bool Gen >
257
258 // removes the top element from the priority queue and return it
259 template < typename Val, typename Priority, typename Cmp, bool Gen >
261 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
262
263 Val v = *(_heap_[0].second);
264 eraseByPos(0);
265
266 return v;
267 }
268
269 // returns a hashtable the keys of which are the values stored in the queue
270 template < typename Val, typename Priority, typename Cmp, bool Gen >
271 INLINE const HashTable< Val, Size >&
273 return reinterpret_cast< const HashTable< Val, Size >& >(_indices_);
274 }
275
276 // inserts a new (a copy) element in the priority queue
277 template < typename Val, typename Priority, typename Cmp, bool Gen >
278 INLINE Size
280 const Priority& priority) {
281 // create the entry in the indices hashtable (if the element already exists,
282 // _indices_.insert will raise a Duplicateelement exception)
283 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
284
285 try {
286 _heap_.push_back(std::pair< Priority, const Val* >(priority, &new_elt.first));
287 } catch (...) {
288 _indices_.erase(val);
289 throw;
290 }
292 std::pair< Priority, const Val* > new_heap_val = std::move(_heap_[_nb_elements_]);
294
295 // restore the heap property
296 Size i = _nb_elements_ - 1;
297
298 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
299 i = j, j = (j - 1) >> 1) {
300 _heap_[i] = std::move(_heap_[j]);
301 _indices_[*(_heap_[i].second)] = i;
302 }
303
304 // put the new bucket into the heap
305 _heap_[i].first = std::move(new_heap_val.first);
306 _heap_[i].second = &(new_elt.first);
307 new_elt.second = i;
308
309 return i;
310 }
312 // inserts by move a new element in the priority queue
313 template < typename Val, typename Priority, typename Cmp, bool Gen >
315 Priority&& priority) {
316 // create the entry in the indices hashtable (if the element already exists,
317 // _indices_.insert will raise a Duplicateelement exception)
318 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(std::move(val), 0);
319
320 try {
321 _heap_.push_back(std::pair< Priority, const Val* >(std::move(priority), &(new_elt.first)));
322 } catch (...) {
323 _indices_.erase(new_elt.first);
324 throw;
326
327 std::pair< Priority, const Val* > new_heap_val = std::move(_heap_[_nb_elements_]);
328 ++_nb_elements_;
329
330 // restore the heap property
331 Size i = _nb_elements_ - 1;
332
333 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
334 i = j, j = (j - 1) >> 1) {
335 _heap_[i] = std::move(_heap_[j]);
336 _indices_[*(_heap_[i].second)] = i;
337 }
338
339 // put the new bucket into the heap
340 _heap_[i].first = std::move(new_heap_val.first);
341 _heap_[i].second = &(new_elt.first);
342 new_elt.second = i;
343
344 return i;
345 }
346
347 // emplace a new element into the priority queue
348 template < typename Val, typename Priority, typename Cmp, bool Gen >
349 template < typename... Args >
351 std::pair< Val, Priority > new_elt
352 = std::make_pair< Val, Priority >(std::forward< Args >(args)...);
353 return insert(std::move(new_elt.first), std::move(new_elt.second));
354 }
356 // indicates whether the priority queue is empty
357 template < typename Val, typename Priority, typename Cmp, bool Gen >
359 return (_nb_elements_ == 0);
360 }
361
362 // indicates whether the priority queue contains a given value
363 template < typename Val, typename Priority, typename Cmp, bool Gen >
364 INLINE bool
366 return _indices_.exists(val);
367 }
368
369 // returns the element at position "index" in the priority queue
370 template < typename Val, typename Priority, typename Cmp, bool Gen >
371 INLINE const Val&
373 if (index >= _nb_elements_) {
374 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
375 }
376
377 return *(_heap_[index].second);
378 }
379
380 // displays the content of the queue
381 template < typename Val, typename Priority, typename Cmp, bool Gen >
383 bool deja = false;
384 std::stringstream stream;
385 stream << "[";
387 for (Size i = 0; i != _nb_elements_; ++i, deja = true) {
388 if (deja) stream << " , ";
389
390 stream << "(" << _heap_[i].first << " , " << *(_heap_[i].second) << ")";
391 }
392
393 stream << "]";
394
395 return stream.str();
396 }
397
398 // changes the size of the internal structure storing the priority queue
399 template < typename Val, typename Priority, typename Cmp, bool Gen >
401 Size index,
402 const Priority& new_priority) {
403 // check whether the element the priority of which should be changed exists
404 if (index >= _nb_elements_) {
405 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
406 }
407
408 // get the element itself
409 const Val* val = _heap_[index].second;
410
411 // restore the heap property
412 Size i = index;
413
414 // move val upward if needed
415 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
416 i = j, j = (j - 1) >> 1) {
417 _heap_[i] = std::move(_heap_[j]);
418 _indices_[*(_heap_[i].second)] = i;
420
421 // move val downward if needed
422 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
423 // let j be the max child
424 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
425
426 // if "val" is lower than heap[j], "val" must be stored at index i
427 if (_cmp_(new_priority, _heap_[j].first)) break;
428
429 // else pull up the jth node
430 _heap_[i] = std::move(_heap_[j]);
431 _indices_[*(_heap_[i].second)] = i;
432 }
433
434 // update the index of val
435 _heap_[i].first = new_priority;
436 _heap_[i].second = val;
437 _indices_[*val] = i;
438
439 return i;
440 }
441
442 // changes the size of the internal structure storing the priority queue
443 template < typename Val, typename Priority, typename Cmp, bool Gen >
445 Size index,
446 Priority&& new_priority) {
447 // check whether the element the priority of which should be changed exists
448 if (index >= _nb_elements_) {
449 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
450 }
451
452 // get the element itself
453 const Val* val = _heap_[index].second;
454
455 // restore the heap property
456 Size i = index;
457
458 // move val upward if needed
459 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
460 i = j, j = (j - 1) >> 1) {
461 _heap_[i] = std::move(_heap_[j]);
462 _indices_[*(_heap_[i].second)] = i;
463 }
464
465 // move val downward if needed
466 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
467 // let j be the max child
468 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
469
470 // if "val" is lower than heap[j], "val" must be stored at index i
471 if (_cmp_(new_priority, _heap_[j].first)) break;
472
473 // else pull up the jth node
474 _heap_[i] = std::move(_heap_[j]);
475 _indices_[*(_heap_[i].second)] = i;
476 }
477
478 // update the index of val
479 _heap_[i].first = std::move(new_priority);
480 _heap_[i].second = val;
481 _indices_[*val] = i;
482
483 return i;
484 }
485
486 // modifies the priority of a given element
487 template < typename Val, typename Priority, typename Cmp, bool Gen >
489 const Val& elt,
490 const Priority& new_priority) {
491 setPriorityByPos(_indices_[elt], new_priority);
492 }
493
494 // modifies the priority of a given element
495 template < typename Val, typename Priority, typename Cmp, bool Gen >
496 void
498 Priority&& new_priority) {
499 setPriorityByPos(_indices_[elt], std::move(new_priority));
500 }
501
502 // returns the priority of a given element
503 template < typename Val, typename Priority, typename Cmp, bool Gen >
504 INLINE const Priority&
506 return _heap_[_indices_[elt]].first;
507 }
508
509 // returns the priority of a given element
510 template < typename Val, typename Priority, typename Cmp, bool Gen >
511 INLINE const Priority&
513 if (index > _nb_elements_) {
514 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
515 }
516 return _heap_[index].first;
517 }
518
519 // ===========================================================================
520 // === SCALAR OPTIMIZED IMPLEMENTATION OF PRIORITY QUEUES ===
521 // ===========================================================================
522
523 // basic constructor
524 template < typename Val, typename Priority, typename Cmp >
526 Cmp compare,
527 Size capacity) : _indices_(capacity >> 1, true, true), _cmp_(compare) {
528 _heap_.reserve(capacity);
529
530 // for debugging purposes
531 GUM_CONSTRUCTOR(PriorityQueueImplementation);
532 }
533
534 // initializer list constructor
535 template < typename Val, typename Priority, typename Cmp >
537 std::initializer_list< std::pair< Val, Priority > > list) :
538 _indices_(Size(list.size()) / 2, true, true) {
539 // fill the queue
540 _heap_.reserve(list.size());
541 for (const auto& elt: list) {
542 insert(elt.first, elt.second);
543 }
544
545 // for debugging purposes
546 GUM_CONSTRUCTOR(PriorityQueueImplementation);
547 }
548
549 // copy constructor
550 template < typename Val, typename Priority, typename Cmp >
553 _heap_(from._heap_), _indices_(from._indices_), _nb_elements_(from._nb_elements_),
554 _cmp_(from._cmp_) {
555 // for debugging purposes
556 GUM_CONS_CPY(PriorityQueueImplementation);
557 }
558
559 // move constructor
560 template < typename Val, typename Priority, typename Cmp >
563 _heap_(std::move(from._heap_)), _indices_(std::move(from._indices_)),
564 _nb_elements_(std::move(from._nb_elements_)), _cmp_(std::move(from._cmp_)) {
565 // for debugging purposes
566 GUM_CONS_MOV(PriorityQueueImplementation);
567 }
568
569 // destructor
570 template < typename Val, typename Priority, typename Cmp >
572 // for debugging purposes
573 GUM_DESTRUCTOR(PriorityQueueImplementation);
574 }
575
576 // copy operator
577 template < typename Val, typename Priority, typename Cmp >
581 // avoid self assignment
582 if (this != &from) {
583 // for debugging purposes
584 GUM_OP_CPY(PriorityQueueImplementation);
585
586 try {
587 // set the comparison function
588 _cmp_ = from._cmp_;
589
590 // copy the indices and the heap
591 _indices_ = from._indices_;
592 _heap_ = from._heap_;
593 _nb_elements_ = from._nb_elements_;
594 } catch (...) {
595 _heap_.clear();
596 _indices_.clear();
597 _nb_elements_ = 0;
598
599 throw;
600 }
601 }
602
603 return *this;
604 }
605
606 // move operator
607 template < typename Val, typename Priority, typename Cmp >
611 // avoid self assignment
612 if (this != &from) {
613 // for debugging purposes
614 GUM_OP_MOV(PriorityQueueImplementation);
615
616 _indices_ = std::move(from._indices_);
617 _heap_ = std::move(from._heap_);
618 _cmp_ = std::move(from._cmp_);
619 _nb_elements_ = std::move(from._nb_elements_);
620 }
621
622 return *this;
623 }
624
625 // returns the element at the top of the priority queue
626 template < typename Val, typename Priority, typename Cmp >
628 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
629
630 return _heap_[0].second;
631 }
632
633 // returns the priority of the top element
634 template < typename Val, typename Priority, typename Cmp >
635 INLINE const Priority&
637 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
638
639 return _heap_[0].first;
640 }
641
642 // returns the number of elements in the priority queue
643 template < typename Val, typename Priority, typename Cmp >
645 return _nb_elements_;
646 }
647
648 // return the size of the array storing the priority queue
649 template < typename Val, typename Priority, typename Cmp >
651 return Size(_heap_.capacity());
652 }
653
654 // changes the size of the array storing the priority queue
655 template < typename Val, typename Priority, typename Cmp >
657 if (new_size < _nb_elements_) return;
658
659 _heap_.reserve(new_size);
660 _indices_.resize(new_size / 2);
661 }
662
663 // removes all the elements from the queue
664 template < typename Val, typename Priority, typename Cmp >
666 _nb_elements_ = 0;
667 _heap_.clear();
668 _indices_.clear();
669 }
670
671 // removes the element at index elt from the priority queue
672 template < typename Val, typename Priority, typename Cmp >
674 if (index >= _nb_elements_) return;
675
676 // remove the element from the hashtable
677 _indices_.erase(_heap_[index].second);
678
679 // put the last element at the "index" location
680 std::pair< Priority, Val > last = std::move(_heap_[_nb_elements_ - 1]);
681 _heap_.pop_back();
682 --_nb_elements_;
683
684 if (!_nb_elements_ || (index == _nb_elements_)) return;
685
686 // restore the heap property
687 Size i = index;
688
689 for (Size j = (index << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
690 // let j be the max child
691 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
692
693 // if "last" is lower than heap[j], "last" must be stored at index i
694 if (_cmp_(last.first, _heap_[j].first)) break;
695
696 // else pull up the jth node
697 _heap_[i] = std::move(_heap_[j]);
698 _indices_[_heap_[i].second] = i;
699 }
700
701 // put "last" back into the heap
702 _heap_[i] = std::move(last);
703 _indices_[_heap_[i].second] = i;
704 }
705
706 // removes a given element from the priority queue (but does not return it)
707 template < typename Val, typename Priority, typename Cmp >
709 try {
710 eraseByPos(_indices_[val]);
711 } catch (NotFound const&) {}
712 }
713
714 // removes the top of the priority queue (but does not return it)
715 template < typename Val, typename Priority, typename Cmp >
717 eraseByPos(0);
718 }
719
720 // removes the top element from the priority queue and return it
721 template < typename Val, typename Priority, typename Cmp >
723 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
724
725 Val v = _heap_[0].second;
726 eraseByPos(0);
727
728 return v;
729 }
730
731 // returns a hashtable the keys of which are the values stored in the queue
732 template < typename Val, typename Priority, typename Cmp >
733 INLINE const HashTable< Val, Size >&
735 return reinterpret_cast< const HashTable< Val, Size >& >(_indices_);
736 }
737
738 // inserts a new (a copy) element in the priority queue
739 template < typename Val, typename Priority, typename Cmp >
740 INLINE Size
742 const Priority& priority) {
743 // create the entry in the indices hashtable (if the element already exists,
744 // _indices_.insert will raise a Duplicateelement exception)
745 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
746
747 try {
748 _heap_.push_back(std::pair< Priority, Val >(priority, val));
749 } catch (...) {
750 _indices_.erase(val);
751 throw;
752 }
753
754 std::pair< Priority, Val > new_heap_val = std::move(_heap_[_nb_elements_]);
755 ++_nb_elements_;
756
757 // restore the heap property
758 Size i = _nb_elements_ - 1;
759
760 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
761 i = j, j = (j - 1) >> 1) {
762 _heap_[i] = std::move(_heap_[j]);
763 _indices_[_heap_[i].second] = i;
764 }
765
766 // put the new bucket into the heap
767 _heap_[i].first = std::move(new_heap_val.first);
768 _heap_[i].second = val;
769 new_elt.second = i;
770
771 return i;
772 }
773
774 // inserts by move a new element in the priority queue
775 template < typename Val, typename Priority, typename Cmp >
777 Priority&& priority) {
778 // create the entry in the indices hashtable (if the element already exists,
779 // _indices_.insert will raise a Duplicateelement exception)
780 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
781
782 try {
783 _heap_.push_back(std::pair< Priority, Val >(std::move(priority), val));
784 } catch (...) {
785 _indices_.erase(val);
786 throw;
787 }
788
789 std::pair< Priority, Val > new_heap_val = std::move(_heap_[_nb_elements_]);
790 ++_nb_elements_;
791
792 // restore the heap property
793 Size i = _nb_elements_ - 1;
794
795 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
796 i = j, j = (j - 1) >> 1) {
797 _heap_[i] = std::move(_heap_[j]);
798 _indices_[_heap_[i].second] = i;
799 }
800
801 // put the new bucket into the heap
802 _heap_[i].first = std::move(new_heap_val.first);
803 _heap_[i].second = val;
804 new_elt.second = i;
805
806 return i;
807 }
808
809 // emplace a new element into the priority queue
810 template < typename Val, typename Priority, typename Cmp >
811 template < typename... Args >
813 std::pair< Val, Priority > new_elt
814 = std::make_pair< Val, Priority >(std::forward< Args >(args)...);
815 return insert(new_elt.first, std::move(new_elt.second));
816 }
817
818 // indicates whether the priority queue is empty
819 template < typename Val, typename Priority, typename Cmp >
821 return (_nb_elements_ == 0);
822 }
823
824 // indicates whether the priority queue contains a given value
825 template < typename Val, typename Priority, typename Cmp >
827 return _indices_.exists(val);
828 }
829
830 // returns the element at position "index" in the priority queue
831 template < typename Val, typename Priority, typename Cmp >
832 INLINE const Val&
834 if (index >= _nb_elements_) {
835 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
836 }
837
838 return _heap_[index].second;
839 }
840
841 // displays the content of the queue
842 template < typename Val, typename Priority, typename Cmp >
844 bool deja = false;
845 std::stringstream stream;
846 stream << "[";
847
848 for (Size i = 0; i != _nb_elements_; ++i, deja = true) {
849 if (deja) stream << " , ";
850
851 stream << "(" << _heap_[i].first << " , " << _heap_[i].second << ")";
852 }
853
854 stream << "]";
855
856 return stream.str();
857 }
858
859 // changes the size of the internal structure storing the priority queue
860 template < typename Val, typename Priority, typename Cmp >
862 Size index,
863 const Priority& new_priority) {
864 // check whether the element the priority of which should be changed exists
865 if (index >= _nb_elements_) {
866 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
867 }
868
869 // get the element itself
870 Val val = _heap_[index].second;
871
872 // restore the heap property
873 Size i = index;
874
875 // move val upward if needed
876 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
877 i = j, j = (j - 1) >> 1) {
878 _heap_[i] = std::move(_heap_[j]);
879 _indices_[_heap_[i].second] = i;
880 }
881
882 // move val downward if needed
883 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
884 // let j be the max child
885 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
886
887 // if "val" is lower than heap[j], "val" must be stored at index i
888 if (_cmp_(new_priority, _heap_[j].first)) break;
889
890 // else pull up the jth node
891 _heap_[i] = std::move(_heap_[j]);
892 _indices_[_heap_[i].second] = i;
893 }
894
895 // update the index of val
896 _heap_[i].first = new_priority;
897 _heap_[i].second = val;
898 _indices_[val] = i;
899
900 return i;
901 }
902
903 // changes the size of the internal structure storing the priority queue
904 template < typename Val, typename Priority, typename Cmp >
906 Size index,
907 Priority&& new_priority) {
908 // check whether the element the priority of which should be changed exists
909 if (index >= _nb_elements_) {
910 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
911 }
913 // get the element itself
914 Val val = _heap_[index].second;
915
916 // restore the heap property
917 Size i = index;
918
919 // move val upward if needed
920 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
921 i = j, j = (j - 1) >> 1) {
922 _heap_[i] = std::move(_heap_[j]);
923 _indices_[_heap_[i].second] = i;
924 }
925
926 // move val downward if needed
927 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
928 // let j be the max child
929 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
930
931 // if "val" is lower than heap[j], "val" must be stored at index i
932 if (_cmp_(new_priority, _heap_[j].first)) break;
933
934 // else pull up the jth node
935 _heap_[i] = std::move(_heap_[j]);
936 _indices_[_heap_[i].second] = i;
937 }
938
939 // update the index of val
940 _heap_[i].first = std::move(new_priority);
941 _heap_[i].second = val;
942 _indices_[val] = i;
943
944 return i;
945 }
946
947 // modifies the priority of a given element
948 template < typename Val, typename Priority, typename Cmp >
950 Val elt,
951 const Priority& new_priority) {
952 setPriorityByPos(_indices_[elt], new_priority);
953 }
954
955 // modifies the priority of a given element
956 template < typename Val, typename Priority, typename Cmp >
958 Val elt,
959 Priority&& new_priority) {
960 setPriorityByPos(_indices_[elt], std::move(new_priority));
961 }
962
963 // returns the priority of a given element
964 template < typename Val, typename Priority, typename Cmp >
965 INLINE const Priority&
967 return _heap_[_indices_[elt]].first;
968 }
969
970 // returns the priority of a given element
971 template < typename Val, typename Priority, typename Cmp >
972 INLINE const Priority&
974 if (index > _nb_elements_) {
975 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
976 }
977 return _heap_[index].first;
978 }
979
980 // ===========================================================================
981 // === PRIORITY QUEUES ===
982 // ===========================================================================
983
984 // basic constructor
985 template < typename Val, typename Priority, typename Cmp >
987 PriorityQueue< Val, Priority, Cmp >::Implementation(cmp, capacity) {
988 // for debugging purposes
989 GUM_CONSTRUCTOR(PriorityQueue);
990 }
991
992 // initializer list constructor
993 template < typename Val, typename Priority, typename Cmp >
995 std::initializer_list< std::pair< Val, Priority > > list) :
996 PriorityQueue< Val, Priority, Cmp >::Implementation{list} {
997 // for debugging purposes
998 GUM_CONSTRUCTOR(PriorityQueue);
999 }
1000
1001 // copy constructor
1002 template < typename Val, typename Priority, typename Cmp >
1005 PriorityQueue< Val, Priority, Cmp >::Implementation(from) {
1006 // for debugging purposes
1007 GUM_CONS_CPY(PriorityQueue);
1008 }
1009
1010 // move constructor
1011 template < typename Val, typename Priority, typename Cmp >
1014 PriorityQueue< Val, Priority, Cmp >::Implementation(std::move(from)) {
1015 // for debugging purposes
1016 GUM_CONS_MOV(PriorityQueue);
1017 }
1018
1019 // destructor
1020 template < typename Val, typename Priority, typename Cmp >
1022 // for debugging purposes
1023 GUM_DESTRUCTOR(PriorityQueue);
1024 }
1025
1026 // copy operator
1027 template < typename Val, typename Priority, typename Cmp >
1033
1034 // move operator
1035 template < typename Val, typename Priority, typename Cmp >
1041
1042 // A \c << operator for priority queues
1043 template < typename Val, typename Priority, typename Cmp >
1044 INLINE std::ostream& operator<<(std::ostream& stream,
1046 stream << queue.toString();
1047 return stream;
1048 }
1049
1050} /* namespace gum */
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:643
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
Exception : the element we looked for cannot be found.
The internal class for representing priority queues.
Size _nb_elements_
The number of elements in the heap.
const Val & operator[](Size index_elt) const
Returns the element at index "index_elt" from the priority queue.
void erase(const Val &val)
Removes a given element from the priority queue (but does not return it).
Size emplace(Args &&... args)
Emplace a new element into the priority queue.
void setPriority(const Val &elt, const Priority &new_priority)
Modifies the priority of each instance of a given element.
void eraseTop()
Removes the top of the priority queue (but does not return it).
Size size() const noexcept
Returns the number of elements in the priority queue.
Val pop()
Removes the top element from the priority queue and return it.
const Val & top() const
returns the element at the top of the priority queue
~PriorityQueueImplementation()
Class destructor.
bool empty() const noexcept
Indicates whether the priority queue is empty.
void clear()
Removes all the elements from the queue.
const Priority & priority(const Val &elt) const
Returns the priority of an instance of the value passed in argument.
void eraseByPos(Size index)
Removes the element at position "index" from the priority queue.
std::string toString() const
Displays the content of the queue.
void resize(Size new_size)
Changes the size of the internal structure storing the priority queue.
PriorityQueueImplementation< Val, Priority, Cmp, Gen > & operator=(const PriorityQueueImplementation< Val, Priority, Cmp, Gen > &from)
Copy operator.
Size insert(const Val &val, const Priority &priority)
Inserts a new (a copy) element in the priority queue.
const Priority & priorityByPos(Size index) const
Returns the priority of the value passed in argument.
Size capacity() const noexcept
Returns the size of the internal structure storing the priority queue.
PriorityQueueImplementation(Cmp compare, Size capacity)
Basic constructor.
HashTable< Val, Size > _indices_
A hashtable for quickly finding the elements by their value.
std::vector< std::pair< Priority, const Val * > > _heap_
An array storing all the elements of the heap as well as their score.
bool contains(const Val &val) const
Indicates whether the priority queue contains a given value.
const HashTable< Val, Size > & allValues() const noexcept
Returns a hashtable the keys of which are the values stored in the queue.
Cmp _cmp_
Comparison function.
Size setPriorityByPos(Size index, const Priority &new_priority)
Modifies the priority of the element at position "index" of the queue.
const Priority & topPriority() const
Returns the priority of the top element.
A priorityQueue is a heap in which each element has a mutable priority.
PriorityQueue< Val, Priority, Cmp > & operator=(const PriorityQueue< Val, Priority, Cmp > &from)
Copy operator.
PriorityQueue(Cmp compare=Cmp(), Size capacity=GUM_PRIORITY_QUEUE_DEFAULT_CAPACITY)
Basic constructor.
PriorityQueueImplementation< Val, Priority, Cmp, std::is_scalar< Val >::value > Implementation
~PriorityQueue()
Class destructor.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
Definition AVLTree.h:913
STL namespace.
priority queues (in which an element cannot appear more than once)