aGrUM 3.1.1
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-2026 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-2026 *
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
41#pragma once
42
43
50
52
53namespace gum {
54
55 // ===========================================================================
56 // === GENERAL IMPLEMENTATIION OF PRIORITY QUEUES ===
57 // ===========================================================================
58
59 // basic constructor
60 template < typename Val, typename Priority, typename Cmp, bool Gen >
68
69 // initializer list constructor
70 template < typename Val, typename Priority, typename Cmp, bool Gen >
72 std::initializer_list< std::pair< Val, Priority > > list) :
73 _indices_(Size(list.size()) / 2, true, true) {
74 // fill the queue
75 _heap_.reserve(list.size());
76 for (const auto& elt: list) {
77 insert(elt.first, elt.second);
78 }
79
80 GUM_CONSTRUCTOR(PriorityQueueImplementation);
81 }
82
83 // copy constructor
84 template < typename Val, typename Priority, typename Cmp, bool Gen >
88 _cmp_(from._cmp_) {
89 // fill the heap structure
90 for (const auto& elt: _indices_) {
91 _heap_[elt.second].second = &(elt.first);
92 }
93
94 GUM_CONS_CPY(PriorityQueueImplementation);
95 }
96
97 // move constructor
98 template < typename Val, typename Priority, typename Cmp, bool Gen >
105
106 // destructor
107 template < typename Val, typename Priority, typename Cmp, bool Gen >
111
112 // copy operator
113 template < typename Val, typename Priority, typename Cmp, bool Gen >
117 // avoid self assignment
118 if (this != &from) {
120
121 try {
122 // set the comparison function
123 _cmp_ = from._cmp_;
124
125 // copy the indices and the heap
126 _indices_ = from._indices_;
127 _heap_ = from._heap_;
129
130 // restore the link between _indices_ and _heap_
131 for (const auto& elt: _indices_) {
132 _heap_[elt.second].second = &(elt.first);
133 }
134 } catch (...) {
135 _heap_.clear();
136 _indices_.clear();
137 _nb_elements_ = 0;
138
139 throw;
140 }
141 }
142
143 return *this;
144 }
145
146 // move operator
147 template < typename Val, typename Priority, typename Cmp, bool Gen >
151 // avoid self assignment
152 if (this != &from) {
154
155 _indices_ = std::move(from._indices_);
156 _heap_ = std::move(from._heap_);
157 _cmp_ = std::move(from._cmp_);
158 _nb_elements_ = std::move(from._nb_elements_);
159 }
160
161 return *this;
162 }
163
164 // returns the element at the top of the priority queue
165 template < typename Val, typename Priority, typename Cmp, bool Gen >
167 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
168
169 return *(_heap_[0].second);
170 }
171
172 // returns the priority of the top element
173 template < typename Val, typename Priority, typename Cmp, bool Gen >
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 >
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 >
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 if (auto ptr = _indices_.tryGet(val)) eraseByPos(*ptr);
248 }
249
250 // removes the top of the priority queue (but does not return it)
251 template < typename Val, typename Priority, typename Cmp, bool Gen >
255
256 // removes the top element from the priority queue and return it
257 template < typename Val, typename Priority, typename Cmp, bool Gen >
259 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
260
261 Val v = *(_heap_[0].second);
262 eraseByPos(0);
263
264 return v;
265 }
266
267 // returns a hashtable the keys of which are the values stored in the queue
268 template < typename Val, typename Priority, typename Cmp, bool Gen >
271 return reinterpret_cast< const HashTable< Val, Size >& >(_indices_);
272 }
273
274 // inserts a new (a copy) element in the priority queue
275 template < typename Val, typename Priority, typename Cmp, bool Gen >
277 const Priority& priority) {
278 // create the entry in the indices hashtable (if the element already exists,
279 // _indices_.insert will raise a Duplicateelement exception)
280 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
281
282 try {
283 _heap_.push_back(std::pair< Priority, const Val* >(priority, &new_elt.first));
284 } catch (...) {
285 _indices_.erase(val);
286 throw;
287 }
288
289 std::pair< Priority, const Val* > new_heap_val = std::move(_heap_[_nb_elements_]);
290 ++_nb_elements_;
292 // restore the heap property
293 Size i = _nb_elements_ - 1;
294
295 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
296 i = j, j = (j - 1) >> 1) {
297 _heap_[i] = std::move(_heap_[j]);
298 _indices_[*(_heap_[i].second)] = i;
299 }
300
301 // put the new bucket into the heap
302 _heap_[i].first = std::move(new_heap_val.first);
303 _heap_[i].second = &(new_elt.first);
304 new_elt.second = i;
305
306 return i;
307 }
308
309 // inserts by move a new element in the priority queue
310 template < typename Val, typename Priority, typename Cmp, bool Gen >
312 Priority&& priority) {
313 // create the entry in the indices hashtable (if the element already exists,
314 // _indices_.insert will raise a Duplicateelement exception)
315 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(std::move(val), 0);
316
317 try {
318 _heap_.push_back(std::pair< Priority, const Val* >(std::move(priority), &(new_elt.first)));
319 } catch (...) {
320 _indices_.erase(new_elt.first);
321 throw;
322 }
323
324 std::pair< Priority, const Val* > new_heap_val = std::move(_heap_[_nb_elements_]);
326
327 // restore the heap property
328 Size i = _nb_elements_ - 1;
329
330 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
331 i = j, j = (j - 1) >> 1) {
332 _heap_[i] = std::move(_heap_[j]);
333 _indices_[*(_heap_[i].second)] = i;
334 }
335
336 // put the new bucket into the heap
337 _heap_[i].first = std::move(new_heap_val.first);
338 _heap_[i].second = &(new_elt.first);
339 new_elt.second = i;
340
341 return i;
342 }
343
344 // emplace a new element into the priority queue
345 template < typename Val, typename Priority, typename Cmp, bool Gen >
346 template < typename... Args >
348 std::pair< Val, Priority > new_elt
349 = std::make_pair< Val, Priority >(std::forward< Args >(args)...);
350 return insert(std::move(new_elt.first), std::move(new_elt.second));
351 }
352
353 // indicates whether the priority queue is empty
354 template < typename Val, typename Priority, typename Cmp, bool Gen >
356 return (_nb_elements_ == 0);
357 }
358
359 // indicates whether the priority queue contains a given value
360 template < typename Val, typename Priority, typename Cmp, bool Gen >
362 return _indices_.exists(val);
363 }
364
365 // returns the element at position "index" in the priority queue
366 template < typename Val, typename Priority, typename Cmp, bool Gen >
368 if (index >= _nb_elements_) {
369 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
370 }
371
372 return *(_heap_[index].second);
373 }
375 // displays the content of the queue
376 template < typename Val, typename Priority, typename Cmp, bool Gen >
378 bool deja = false;
379 std::stringstream stream;
380 stream << "[";
382 for (Size i = 0; i != _nb_elements_; ++i, deja = true) {
383 if (deja) stream << " , ";
384
385 stream << "(" << _heap_[i].first << " , " << *(_heap_[i].second) << ")";
387
388 stream << "]";
389
390 return stream.str();
391 }
392
393 // changes the size of the internal structure storing the priority queue
394 template < typename Val, typename Priority, typename Cmp, bool Gen >
396 Size index,
397 const Priority& new_priority) {
398 // check whether the element the priority of which should be changed exists
399 if (index >= _nb_elements_) {
400 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
401 }
402
403 // get the element itself
404 const Val* val = _heap_[index].second;
406 // restore the heap property
407 Size i = index;
408
409 // move val upward if needed
410 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
411 i = j, j = (j - 1) >> 1) {
412 _heap_[i] = std::move(_heap_[j]);
413 _indices_[*(_heap_[i].second)] = i;
414 }
415
416 // move val downward if needed
417 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
418 // let j be the max child
419 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
420
421 // if "val" is lower than heap[j], "val" must be stored at index i
422 if (_cmp_(new_priority, _heap_[j].first)) break;
423
424 // else pull up the jth node
425 _heap_[i] = std::move(_heap_[j]);
426 _indices_[*(_heap_[i].second)] = i;
427 }
428
429 // update the index of val
430 _heap_[i].first = new_priority;
431 _heap_[i].second = val;
432 _indices_[*val] = i;
433
434 return i;
435 }
436
437 // changes the size of the internal structure storing the priority queue
438 template < typename Val, typename Priority, typename Cmp, bool Gen >
440 Size index,
441 Priority&& new_priority) {
442 // check whether the element the priority of which should be changed exists
443 if (index >= _nb_elements_) {
444 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
445 }
446
447 // get the element itself
448 const Val* val = _heap_[index].second;
449
450 // restore the heap property
451 Size i = index;
452
453 // move val upward if needed
454 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
455 i = j, j = (j - 1) >> 1) {
456 _heap_[i] = std::move(_heap_[j]);
457 _indices_[*(_heap_[i].second)] = i;
458 }
459
460 // move val downward if needed
461 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
462 // let j be the max child
463 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
464
465 // if "val" is lower than heap[j], "val" must be stored at index i
466 if (_cmp_(new_priority, _heap_[j].first)) break;
467
468 // else pull up the jth node
469 _heap_[i] = std::move(_heap_[j]);
470 _indices_[*(_heap_[i].second)] = i;
471 }
472
473 // update the index of val
474 _heap_[i].first = std::move(new_priority);
475 _heap_[i].second = val;
476 _indices_[*val] = i;
477
478 return i;
479 }
480
481 // modifies the priority of a given element
482 template < typename Val, typename Priority, typename Cmp, bool Gen >
484 const Val& elt,
485 const Priority& new_priority) {
486 setPriorityByPos(_indices_[elt], new_priority);
487 }
488
489 // modifies the priority of a given element
490 template < typename Val, typename Priority, typename Cmp, bool Gen >
491 void
493 Priority&& new_priority) {
494 setPriorityByPos(_indices_[elt], std::move(new_priority));
495 }
496
497 // returns the priority of a given element
498 template < typename Val, typename Priority, typename Cmp, bool Gen >
499 const Priority&
501 return _heap_[_indices_[elt]].first;
502 }
503
504 // returns the priority of a given element
505 template < typename Val, typename Priority, typename Cmp, bool Gen >
506 const Priority&
508 if (index > _nb_elements_) {
509 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
510 }
511 return _heap_[index].first;
512 }
513
514 // ===========================================================================
515 // === SCALAR OPTIMIZED IMPLEMENTATION OF PRIORITY QUEUES ===
516 // ===========================================================================
517
518 // basic constructor
519 template < typename Val, typename Priority, typename Cmp >
521 Cmp compare,
522 Size capacity) : _indices_(capacity >> 1, true, true), _cmp_(compare) {
523 _heap_.reserve(capacity);
524
525 // for debugging purposes
526 GUM_CONSTRUCTOR(PriorityQueueImplementation);
527 }
528
529 // initializer list constructor
530 template < typename Val, typename Priority, typename Cmp >
532 std::initializer_list< std::pair< Val, Priority > > list) :
533 _indices_(Size(list.size()) / 2, true, true) {
534 // fill the queue
535 _heap_.reserve(list.size());
536 for (const auto& elt: list) {
537 insert(elt.first, elt.second);
538 }
539
540 // for debugging purposes
541 GUM_CONSTRUCTOR(PriorityQueueImplementation);
542 }
543
544 // copy constructor
545 template < typename Val, typename Priority, typename Cmp >
548 _heap_(from._heap_), _indices_(from._indices_), _nb_elements_(from._nb_elements_),
549 _cmp_(from._cmp_) {
550 // for debugging purposes
551 GUM_CONS_CPY(PriorityQueueImplementation);
552 }
553
554 // move constructor
555 template < typename Val, typename Priority, typename Cmp >
558 _heap_(std::move(from._heap_)), _indices_(std::move(from._indices_)),
559 _nb_elements_(std::move(from._nb_elements_)), _cmp_(std::move(from._cmp_)) {
560 // for debugging purposes
561 GUM_CONS_MOV(PriorityQueueImplementation);
562 }
563
564 // destructor
565 template < typename Val, typename Priority, typename Cmp >
567 // for debugging purposes
568 GUM_DESTRUCTOR(PriorityQueueImplementation);
569 }
570
571 // copy operator
572 template < typename Val, typename Priority, typename Cmp >
576 // avoid self assignment
577 if (this != &from) {
578 // for debugging purposes
579 GUM_OP_CPY(PriorityQueueImplementation);
580
581 try {
582 // set the comparison function
583 _cmp_ = from._cmp_;
584
585 // copy the indices and the heap
586 _indices_ = from._indices_;
587 _heap_ = from._heap_;
588 _nb_elements_ = from._nb_elements_;
589 } catch (...) {
590 _heap_.clear();
591 _indices_.clear();
592 _nb_elements_ = 0;
593
594 throw;
595 }
596 }
597
598 return *this;
599 }
600
601 // move operator
602 template < typename Val, typename Priority, typename Cmp >
606 // avoid self assignment
607 if (this != &from) {
608 // for debugging purposes
609 GUM_OP_MOV(PriorityQueueImplementation);
610
611 _indices_ = std::move(from._indices_);
612 _heap_ = std::move(from._heap_);
613 _cmp_ = std::move(from._cmp_);
614 _nb_elements_ = std::move(from._nb_elements_);
615 }
616
617 return *this;
618 }
619
620 // returns the element at the top of the priority queue
621 template < typename Val, typename Priority, typename Cmp >
623 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
624
625 return _heap_[0].second;
626 }
627
628 // returns the priority of the top element
629 template < typename Val, typename Priority, typename Cmp >
631 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
632
633 return _heap_[0].first;
634 }
635
636 // returns the number of elements in the priority queue
637 template < typename Val, typename Priority, typename Cmp >
639 return _nb_elements_;
640 }
641
642 // return the size of the array storing the priority queue
643 template < typename Val, typename Priority, typename Cmp >
645 return Size(_heap_.capacity());
646 }
647
648 // changes the size of the array storing the priority queue
649 template < typename Val, typename Priority, typename Cmp >
651 if (new_size < _nb_elements_) return;
652
653 _heap_.reserve(new_size);
654 _indices_.resize(new_size / 2);
655 }
656
657 // removes all the elements from the queue
658 template < typename Val, typename Priority, typename Cmp >
660 _nb_elements_ = 0;
661 _heap_.clear();
662 _indices_.clear();
663 }
664
665 // removes the element at index elt from the priority queue
666 template < typename Val, typename Priority, typename Cmp >
668 if (index >= _nb_elements_) return;
669
670 // remove the element from the hashtable
671 _indices_.erase(_heap_[index].second);
672
673 // put the last element at the "index" location
674 std::pair< Priority, Val > last = std::move(_heap_[_nb_elements_ - 1]);
675 _heap_.pop_back();
676 --_nb_elements_;
677
678 if (!_nb_elements_ || (index == _nb_elements_)) return;
679
680 // restore the heap property
681 Size i = index;
682
683 for (Size j = (index << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
684 // let j be the max child
685 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
686
687 // if "last" is lower than heap[j], "last" must be stored at index i
688 if (_cmp_(last.first, _heap_[j].first)) break;
689
690 // else pull up the jth node
691 _heap_[i] = std::move(_heap_[j]);
692 _indices_[_heap_[i].second] = i;
693 }
694
695 // put "last" back into the heap
696 _heap_[i] = std::move(last);
697 _indices_[_heap_[i].second] = i;
698 }
699
700 // removes a given element from the priority queue (but does not return it)
701 template < typename Val, typename Priority, typename Cmp >
703 if (auto ptr = _indices_.tryGet(val)) eraseByPos(*ptr);
704 }
705
706 // removes the top of the priority queue (but does not return it)
707 template < typename Val, typename Priority, typename Cmp >
709 eraseByPos(0);
710 }
711
712 // removes the top element from the priority queue and return it
713 template < typename Val, typename Priority, typename Cmp >
715 if (!_nb_elements_) { GUM_ERROR(NotFound, "empty priority queue") }
716
717 Val v = _heap_[0].second;
718 eraseByPos(0);
719
720 return v;
721 }
722
723 // returns a hashtable the keys of which are the values stored in the queue
724 template < typename Val, typename Priority, typename Cmp >
727 return reinterpret_cast< const HashTable< Val, Size >& >(_indices_);
728 }
729
730 // inserts a new (a copy) element in the priority queue
731 template < typename Val, typename Priority, typename Cmp >
733 const Priority& priority) {
734 // create the entry in the indices hashtable (if the element already exists,
735 // _indices_.insert will raise a Duplicateelement exception)
736 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
737
738 try {
739 _heap_.push_back(std::pair< Priority, Val >(priority, val));
740 } catch (...) {
741 _indices_.erase(val);
742 throw;
743 }
744
745 std::pair< Priority, Val > new_heap_val = std::move(_heap_[_nb_elements_]);
746 ++_nb_elements_;
747
748 // restore the heap property
749 Size i = _nb_elements_ - 1;
750
751 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
752 i = j, j = (j - 1) >> 1) {
753 _heap_[i] = std::move(_heap_[j]);
754 _indices_[_heap_[i].second] = i;
755 }
756
757 // put the new bucket into the heap
758 _heap_[i].first = std::move(new_heap_val.first);
759 _heap_[i].second = val;
760 new_elt.second = i;
761
762 return i;
763 }
764
765 // inserts by move a new element in the priority queue
766 template < typename Val, typename Priority, typename Cmp >
768 Priority&& priority) {
769 // create the entry in the indices hashtable (if the element already exists,
770 // _indices_.insert will raise a Duplicateelement exception)
771 typename HashTable< Val, Size >::value_type& new_elt = _indices_.insert(val, 0);
772
773 try {
774 _heap_.push_back(std::pair< Priority, Val >(std::move(priority), val));
775 } catch (...) {
776 _indices_.erase(val);
777 throw;
778 }
779
780 std::pair< Priority, Val > new_heap_val = std::move(_heap_[_nb_elements_]);
781 ++_nb_elements_;
782
783 // restore the heap property
784 Size i = _nb_elements_ - 1;
785
786 for (Size j = (i - 1) >> 1; i && _cmp_(new_heap_val.first, _heap_[j].first);
787 i = j, j = (j - 1) >> 1) {
788 _heap_[i] = std::move(_heap_[j]);
789 _indices_[_heap_[i].second] = i;
790 }
791
792 // put the new bucket into the heap
793 _heap_[i].first = std::move(new_heap_val.first);
794 _heap_[i].second = val;
795 new_elt.second = i;
796
797 return i;
798 }
799
800 // emplace a new element into the priority queue
801 template < typename Val, typename Priority, typename Cmp >
802 template < typename... Args >
804 std::pair< Val, Priority > new_elt
805 = std::make_pair< Val, Priority >(std::forward< Args >(args)...);
806 return insert(new_elt.first, std::move(new_elt.second));
807 }
808
809 // indicates whether the priority queue is empty
810 template < typename Val, typename Priority, typename Cmp >
812 return (_nb_elements_ == 0);
813 }
814
815 // indicates whether the priority queue contains a given value
816 template < typename Val, typename Priority, typename Cmp >
818 return _indices_.exists(val);
819 }
820
821 // returns the element at position "index" in the priority queue
822 template < typename Val, typename Priority, typename Cmp >
824 if (index >= _nb_elements_) {
825 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
826 }
827
828 return _heap_[index].second;
829 }
830
831 // displays the content of the queue
832 template < typename Val, typename Priority, typename Cmp >
834 bool deja = false;
835 std::stringstream stream;
836 stream << "[";
837
838 for (Size i = 0; i != _nb_elements_; ++i, deja = true) {
839 if (deja) stream << " , ";
840
841 stream << "(" << _heap_[i].first << " , " << _heap_[i].second << ")";
842 }
843
844 stream << "]";
845
846 return stream.str();
847 }
848
849 // changes the size of the internal structure storing the priority queue
850 template < typename Val, typename Priority, typename Cmp >
852 Size index,
853 const Priority& new_priority) {
854 // check whether the element the priority of which should be changed exists
855 if (index >= _nb_elements_) {
856 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
857 }
858
859 // get the element itself
860 Val val = _heap_[index].second;
861
862 // restore the heap property
863 Size i = index;
864
865 // move val upward if needed
866 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
867 i = j, j = (j - 1) >> 1) {
868 _heap_[i] = std::move(_heap_[j]);
869 _indices_[_heap_[i].second] = i;
870 }
871
872 // move val downward if needed
873 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
874 // let j be the max child
875 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
876
877 // if "val" is lower than heap[j], "val" must be stored at index i
878 if (_cmp_(new_priority, _heap_[j].first)) break;
879
880 // else pull up the jth node
881 _heap_[i] = std::move(_heap_[j]);
882 _indices_[_heap_[i].second] = i;
883 }
884
885 // update the index of val
886 _heap_[i].first = new_priority;
887 _heap_[i].second = val;
888 _indices_[val] = i;
889
890 return i;
891 }
892
893 // changes the size of the internal structure storing the priority queue
894 template < typename Val, typename Priority, typename Cmp >
896 Size index,
897 Priority&& new_priority) {
898 // check whether the element the priority of which should be changed exists
899 if (index >= _nb_elements_) {
900 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
901 }
902
903 // get the element itself
904 Val val = _heap_[index].second;
905
906 // restore the heap property
907 Size i = index;
908
909 // move val upward if needed
910 for (Size j = (i - 1) >> 1; i && _cmp_(new_priority, _heap_[j].first);
911 i = j, j = (j - 1) >> 1) {
912 _heap_[i] = std::move(_heap_[j]);
913 _indices_[_heap_[i].second] = i;
914 }
915
916 // move val downward if needed
917 for (Size j = (i << 1) + 1; j < _nb_elements_; i = j, j = (j << 1) + 1) {
918 // let j be the max child
919 if ((j + 1 < _nb_elements_) && _cmp_(_heap_[j + 1].first, _heap_[j].first)) ++j;
920
921 // if "val" is lower than heap[j], "val" must be stored at index i
922 if (_cmp_(new_priority, _heap_[j].first)) break;
923
924 // else pull up the jth node
925 _heap_[i] = std::move(_heap_[j]);
926 _indices_[_heap_[i].second] = i;
927 }
928
929 // update the index of val
930 _heap_[i].first = std::move(new_priority);
931 _heap_[i].second = val;
932 _indices_[val] = i;
933
934 return i;
935 }
936
937 // modifies the priority of a given element
938 template < typename Val, typename Priority, typename Cmp >
940 Val elt,
941 const Priority& new_priority) {
942 setPriorityByPos(_indices_[elt], new_priority);
943 }
944
945 // modifies the priority of a given element
946 template < typename Val, typename Priority, typename Cmp >
948 Val elt,
949 Priority&& new_priority) {
950 setPriorityByPos(_indices_[elt], std::move(new_priority));
951 }
952
953 // returns the priority of a given element
954 template < typename Val, typename Priority, typename Cmp >
956 return _heap_[_indices_[elt]].first;
957 }
958
959 // returns the priority of a given element
960 template < typename Val, typename Priority, typename Cmp >
961 const Priority&
963 if (index > _nb_elements_) {
964 GUM_ERROR(NotFound, "not enough elements in the PriorityQueueImplementation")
965 }
966 return _heap_[index].first;
967 }
968
969 // ===========================================================================
970 // === PRIORITY QUEUES ===
971 // ===========================================================================
972
973 // basic constructor
974 template < typename Val, typename Priority, typename Cmp >
976 PriorityQueue< Val, Priority, Cmp >::Implementation(cmp, capacity) {
977 // for debugging purposes
978 GUM_CONSTRUCTOR(PriorityQueue);
979 }
980
981 // initializer list constructor
982 template < typename Val, typename Priority, typename Cmp >
984 std::initializer_list< std::pair< Val, Priority > > list) :
985 PriorityQueue< Val, Priority, Cmp >::Implementation{list} {
986 // for debugging purposes
987 GUM_CONSTRUCTOR(PriorityQueue);
988 }
989
990 // copy constructor
991 template < typename Val, typename Priority, typename Cmp >
994 PriorityQueue< Val, Priority, Cmp >::Implementation(from) {
995 // for debugging purposes
996 GUM_CONS_CPY(PriorityQueue);
997 }
998
999 // move constructor
1000 template < typename Val, typename Priority, typename Cmp >
1002 PriorityQueue< Val, Priority, Cmp >::Implementation(std::move(from)) {
1003 // for debugging purposes
1004 GUM_CONS_MOV(PriorityQueue);
1005 }
1006
1007 // destructor
1008 template < typename Val, typename Priority, typename Cmp >
1010 // for debugging purposes
1011 GUM_DESTRUCTOR(PriorityQueue);
1012 }
1013
1014 // copy operator
1015 template < typename Val, typename Priority, typename Cmp >
1021
1022 // move operator
1023 template < typename Val, typename Priority, typename Cmp >
1029
1030 // A \c << operator for priority queues
1031 template < typename Val, typename Priority, typename Cmp >
1032 std::ostream& operator<<(std::ostream& stream, const PriorityQueue< Val, Priority, Cmp >& queue) {
1033 stream << queue.toString();
1034 return stream;
1035 }
1036
1037} /* namespace gum */
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:646
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 Priority & priorityByPos(Size index) const
Returns the priority of the value passed in argument.
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 erase(const Val &val)
Removes a given element from the priority queue (but does not return it).
~PriorityQueueImplementation()
Class destructor.
Size insert(const Val &val, const Priority &priority)
Inserts a new (a copy) element in the priority queue.
const Priority & topPriority() const
Returns the priority of the top element.
void resize(Size new_size)
Changes the size of the internal structure storing the priority queue.
void eraseByPos(Size index)
Removes the element at position "index" from the priority queue.
std::string toString() const
Displays the content of the queue.
PriorityQueueImplementation< Val, Priority, Cmp, Gen > & operator=(const PriorityQueueImplementation< Val, Priority, Cmp, Gen > &from)
Copy operator.
void clear()
Removes all the elements from the queue.
const Val & operator[](Size index_elt) const
Returns the element at index "index_elt" from the priority queue.
Size capacity() const noexcept
Returns the size of the internal structure storing the priority queue.
PriorityQueueImplementation(Cmp compare, Size capacity)
Basic constructor.
bool contains(const Val &val) const
Indicates whether the priority queue contains a given value.
const Val & top() const
returns the element at the top of the priority queue
Size size() const noexcept
Returns the number of elements in the priority queue.
const HashTable< Val, Size > & allValues() const noexcept
Returns a hashtable the keys of which are the values stored in the queue.
void eraseTop()
Removes the top of the priority queue (but does not return it).
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.
const Priority & priority(const Val &elt) const
Returns the priority of an instance of the value passed in argument.
Cmp _cmp_
Comparison function.
Val pop()
Removes the top element from the priority queue and return it.
Size setPriorityByPos(Size index, const Priority &new_priority)
Modifies the priority of the element at position "index" of the queue.
bool empty() const noexcept
Indicates whether the priority queue is empty.
A priorityQueue is a heap in which each element has a mutable priority.
PriorityQueueImplementation< Val, Priority, Cmp, std::is_scalar< Val >::value > Implementation
~PriorityQueue()
Class destructor.
PriorityQueue(Cmp compare=Cmp(), Size capacity=GUM_PRIORITY_QUEUE_DEFAULT_CAPACITY)
Basic constructor.
PriorityQueue< Val, Priority, Cmp > & operator=(const PriorityQueue< Val, Priority, Cmp > &from)
Copy operator.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
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
STL namespace.
priority queues (in which an element cannot appear more than once)