aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
priorityQueue.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 priority queues (in which an element cannot appear more than once)
25  *
26  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27  *
28  */
29 
30 #ifndef GUM_PRIORITY_QUEUE_H
31 #define GUM_PRIORITY_QUEUE_H
32 
33 #include <functional>
34 #include <initializer_list>
35 #include <sstream>
36 #include <string>
37 #include <type_traits>
38 #include <utility>
39 #include <vector>
40 
41 #include <agrum/agrum.h>
42 #include <agrum/tools/core/hashTable.h>
43 
44 namespace gum {
45 
46 #define GUM_PRIORITY_QUEUE_DEFAULT_CAPACITY 10
47 
48  // templates provided by this file
49  template < typename Val, typename Priority, typename Cmp, typename Alloc >
50  class PriorityQueue;
51  template < typename Val, typename Priority, typename Cmp, typename Alloc >
52  std::ostream& operator<<(std::ostream&,
53  const PriorityQueue< Val, Priority, Cmp, Alloc >&);
54 
55  // ===========================================================================
56  // === GENERAL IMPLEMENTATION OF PRIORITY QUEUES ===
57  // ===========================================================================
58 
59  /**
60  * @class PriorityQueueImplementation
61  * @headerfile priorityQueue.h <agrum/tools/core/priorityQueue.h>
62  * @ingroup priorityqueue_group
63  * @brief The internal class for representing priority queues.
64  *
65  * Priority Queues have different implementations depending on the nature of
66  * the values they store. Basically, scalar values can lead to optimization
67  * of the code whereas general types like classes cannot. The current class
68  * is used for general types (and therefore for classes). The user shall not
69  * use directly the implementation but rather use the PriorityQueue class.
70  * The latter will be assigned the best implementation at compile time.
71  *
72  * @tparam Val The values type.
73  * @tparam Priority The priorities type.
74  * @tparam Cmp The priorities comparator.
75  * @tparam Alloc The values allocator.
76  * @tparam Gen Used for metaprogramation, for scalar and non-scalar priority
77  * queues.
78  */
79  template < typename Val,
80  typename Priority,
81  typename Cmp,
82  typename Alloc,
83  bool Gen >
84  class PriorityQueueImplementation {
85  /// All gum::PriorityQueue are friends with themselves.
86  friend class PriorityQueue< Val, Priority, Cmp, Alloc >;
87 
88  /// All gum::PriorityQueueImplementation are friends with themselves.
89  template < typename V, typename P, typename C, typename A, bool g >
90  friend class PriorityQueueImplementation;
91 
92  public:
93  /// Types for STL compliance.
94  /// @{
95  using value_type = Val;
96  using reference = Val&;
97  using const_reference = const Val&;
98  using pointer = Val*;
99  using const_pointer = const Val*;
100  using difference_type = std::ptrdiff_t;
101  using allocator_type = Alloc;
102  /// @}
103 
104  // The allocator for the indices.
105  using IndexAllocator =
106  typename Alloc::template rebind< std::pair< Val, Size > >::other;
107 
108  // The allocator for the heap.
109  using HeapAllocator =
110  typename Alloc::template rebind< std::pair< Priority, const Val* > >::other;
111 
112  private:
113  // ============================================================================
114  /// @name Constructors / Destructors
115  // ============================================================================
116  /// @{
117 
118  /**
119  * @brief Basic constructor. Creates an empty priority queue.
120  *
121  * @param compare A function taking two elements in argument, say e1 and
122  * e2, and returning a Boolean indicating wether e1 < e2, i.e., whether e1
123  * should be nearer than e2 to the top of the heap.
124  * @param capacity The size of the internal data structures containing the
125  * elements (could be for instance vectors or hashtables)
126  */
127  explicit PriorityQueueImplementation(Cmp compare, Size capacity);
128 
129  /**
130  * @brief Initializer list constructor.
131  *
132  * The elements of the initializer list are pairs <Val,Priority>. The
133  * comparison function is the default one, i.e., std::less<Priority>.
134  *
135  * @param list The initializer list.
136  */
137  explicit PriorityQueueImplementation(
138  std::initializer_list< std::pair< Val, Priority > > list);
139 
140  /**
141  * @brief Copy constructor.
142  * @param from The gum::PriorityQueueImplementation to copy.
143  */
144  PriorityQueueImplementation(
145  const PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >& from);
146 
147  /**
148  * @brief Generalized copy constructor.
149  * @tparam OtherAlloc The other gum::PriorityQueueImplementation allocator.
150  * @param from The gum::PriorityQueueImplementation to copy.
151  */
152  template < typename OtherAlloc >
153  PriorityQueueImplementation(
154  const PriorityQueueImplementation< Val, Priority, Cmp, OtherAlloc, Gen >&
155  from);
156 
157  /**
158  * @brief Move constructor.
159  * @param from The gum::PriorityQueueImplementation to move.
160  */
161  PriorityQueueImplementation(
162  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >&& from);
163 
164  /**
165  * @brief Class destructor.
166  */
167  ~PriorityQueueImplementation();
168 
169  /// @}
170 
171  public:
172  // ============================================================================
173  /// @name Operators
174  // ============================================================================
175  /// @{
176 
177  /**
178  * @brief Copy operator.
179  *
180  * When a problem occurs during the copy (for instance when not enough
181  * memory is available), the operator guarantees that the heap stays in a
182  * coherent state. Actually, the priority queue becomes empty. An exception
183  * is then thrown.
184  *
185  * @param from The gum::PriorityQueueImplementation to copy.
186  * @return Returns this gum::PriorityQueueImplementation.
187  */
188  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >& operator=(
189  const PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >& from);
190 
191  /**
192  * @brief Generalized copy operator.
193  *
194  * When a problem occurs during the copy (for instance when not enough
195  * memory is available), the operator guarantees that the heap stays in a
196  * coherent state. Actually, the priority queue becomes empty. An exception
197  * is then thrown.
198  *
199  * @tparam OtherAlloc The other gum::PriorityQueueImplementation allocator.
200  * @param from The gum::PriorityQueueImplementation to copy.
201  * @return Returns this gum::PriorityQueueImplementation.
202  */
203  template < typename OtherAlloc >
204  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >& operator=(
205  const PriorityQueueImplementation< Val, Priority, Cmp, OtherAlloc, Gen >&
206  from);
207 
208  /**
209  * @brief Move operator.
210  *
211  * @param from The gum::PriorityQueueImplementation to move.
212  * @return Returns this gum::PriorityQueueImplementation.
213  */
214  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >& operator=(
215  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, Gen >&& from);
216 
217  /**
218  * @brief Returns the element at index "index_elt" from the priority queue.
219  * @param index_elt The index of the element to return.
220  * @return Returns the element at index "index_elt" from the priority
221  * queue.
222  * @throw NotFound Raised if the element does not exist.
223  */
224  const Val& operator[](Size index_elt) const;
225 
226  /// @}
227  // ============================================================================
228  /// @name Accessors / Modifiers
229  // ============================================================================
230  /// @{
231 
232  /**
233  * @brief Returns the number of elements in the priority queue.
234  * @return Returns the number of elements in the priority queue.
235  */
236  Size size() const noexcept;
237 
238  /**
239  * @brief Indicates whether the priority queue is empty.
240  * @return Returns true if the priority queue is empty.
241  */
242  bool empty() const noexcept;
243 
244  /**
245  * @brief Indicates whether the priority queue contains a given value.
246  * @param val The value to look for.
247  * @return Returns true if val is in the priority queue.
248  */
249  bool contains(const Val& val) const;
250 
251  /// returns the element at the top of the priority queue
252  /** @throw NotFound Raised if the queue is empty */
253  const Val& top() const;
254 
255  /**
256  * @brief Returns the priority of the top element.
257  * @return Returns the priority of the top element.
258  * @throw NotFound Raised if the queue is empty.
259  */
260  const Priority& topPriority() const;
261 
262  /**
263  * @brief Removes the top element from the priority queue and return it.
264  * @return Returns the top element from the priority queue.
265  * @throw NotFound Raised if the queue is empty.
266  */
267  Val pop();
268 
269  /**
270  * @brief Inserts a new (a copy) element in the priority queue.
271  *
272  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
273  * about the index.
274  *
275  * @param val The value to insert.
276  * @param priority The value's priority in the queue.
277  * @return Returns the index of the element inserted into the priority
278  * queue.
279  * @throw DuplicateElement Raised if the element already exists.
280  */
281  Size insert(const Val& val, const Priority& priority);
282 
283  /**
284  * @brief Inserts (by move) a new element in the priority queue.
285  *
286  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
287  * about the index.
288  *
289  * @param val The value to insert.
290  * @param priority The value's priority in the queue.
291  * @return Returns the index of the element inserted into the priority
292  * queue.
293  * @throw DuplicateElement Raised if the element already exists.
294  */
295  Size insert(Val&& val, Priority&& priority);
296 
297  /**
298  * @brief Emplace a new element into the priority queue.
299  *
300  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
301  * about the index.
302  *
303  * @tparam Args The emplace arguments types.
304  * @param args The emplace arguments.
305  * @return Returns the index of the element inserted into the priority
306  * queue.
307  * @throw DuplicateElement Raised if the element already exists.
308  */
309  template < typename... Args >
310  Size emplace(Args&&... args);
311 
312  /**
313  * @brief Removes the top of the priority queue (but does not return it).
314  *
315  * If the heap is empty, it does nothing (in particular, it does not throw
316  * any exception).
317  */
318  void eraseTop();
319 
320  /**
321  * @brief Removes the element at position "index" from the priority queue.
322  *
323  * If the element cannot be found, the function returns without throwing
324  * any exception.
325  *
326  * The priority is computed as follows: suppose that the queue is a
327  * complete binary tree where all levels are completely filled except,
328  * eventually, the last one. In this case, the elements of the last
329  * level are all on the left of the tree.
330  *
331  * We assign 0 to the root, then parsing the tree from top to bottom then
332  * from left to right we increment the index and assigned it to the current
333  * node. Doing so, we get a unique index for each element. This is
334  * precisely what the index passed in argument of the function represents.
335  *
336  * @param index represents the position of the element to be removed.
337  */
338  void eraseByPos(Size index);
339 
340  /**
341  * @brief Removes a given element from the priority queue (but does not
342  * return it).
343  *
344  * If the element cannot be found, the function returns without throwing
345  * any exception.
346  *
347  * If the queue contains several times this element, then the one with the
348  * smallest index is removed.
349  *
350  * @param val the element we wish to remove.
351  */
352  void erase(const Val& val);
353 
354  /**
355  * @brief Modifies the priority of the element at position "index" of the
356  * queue.
357  *
358  * @param index The index of the element to update.
359  * @param new_priority The element's new priority.
360  * @return Returns the elements new priority.
361  * @throw NotFound Raised if the element cannot be found.
362  */
363  Size setPriorityByPos(Size index, const Priority& new_priority);
364 
365  /**
366  * @brief Modifies the priority of the element at position "index" of the
367  * queue.
368  *
369  * @param index The index of the element to update.
370  * @param new_priority The element's new priority.
371  * @return Returns the elements new priority.
372  * @throw NotFound Raised if the element cannot be found.
373  */
374  Size setPriorityByPos(Size index, Priority&& new_priority);
375 
376  /**
377  * @brief Modifies the priority of each instance of a given element.
378  * @param elt The value to update.
379  * @param new_priority The values new priority.
380  * @throw NotFound Raised if the element cannot be found.
381  */
382  void setPriority(const Val& elt, const Priority& new_priority);
383 
384  /**
385  * @brief Modifies the priority of each instance of a given element.
386  * @param elt The value to update.
387  * @param new_priority The values new priority.
388  * @throw NotFound Raised if the element cannot be found.
389  */
390  void setPriority(const Val& elt, Priority&& new_priority);
391 
392  /**
393  * @brief Returns the priority of an instance of the value passed in
394  * argument.
395  *
396  * @param elt The element for which the priority is returned.
397  * @return Returns the priority of an instance of the value passed in
398  * argument.
399  * @throw NotFound Raised if the element cannot be found.
400  */
401  const Priority& priority(const Val& elt) const;
402 
403  /**
404  * @brief Returns the priority of the value passed in argument.
405  * @param index The index of the value of which the priority is returned.
406  * @throw NotFound Raised if the element cannot be found.
407  */
408  const Priority& priorityByPos(Size index) const;
409 
410  /**
411  * @brief Removes all the elements from the queue.
412  */
413  void clear();
414 
415  /**
416  * @brief Returns a hashtable the keys of which are the values stored in
417  * the queue.
418  *
419  * The keys of the hashtable correspond to the values stored in the
420  * priority queue and, for each key, the corresponding value is the index
421  * in the queue where we can find the key.
422  *
423  * @return Returns a hashtable the keys of which are the values stored in
424  * the queue.
425  */
426  const HashTable< Val, Size >& allValues() const noexcept;
427 
428  /**
429  * @brief Displays the content of the queue.
430  * @return Returns the content of the queue.
431  */
432  std::string toString() const;
433 
434  /// @}
435  // ============================================================================
436  /// @name Fine tuning
437  // ============================================================================
438  /// @{
439 
440  /**
441  * @brief Returns the size of the internal structure storing the priority
442  * queue.
443  * @return Returns the size of the internal structure storing the priority
444  * queue.
445  */
446  Size capacity() const noexcept;
447 
448  /**
449  * @brief Changes the size of the internal structure storing the priority
450  * queue.
451  * @param new_size The internal structure new size.
452  */
453  void resize(Size new_size);
454 
455  /// @}
456 
457  private:
458  /// An array storing all the elements of the heap as well as their score.
459  std::vector< std::pair< Priority, const Val* >, HeapAllocator > heap__;
460 
461  /// A hashtable for quickly finding the elements by their value.
462  HashTable< Val, Size, IndexAllocator > indices__{HashTableConst::default_size,
463  true,
464  true};
465 
466  /// The number of elements in the heap.
467  Size nb_elements__{0};
468 
469  /// Comparison function.
470  Cmp cmp__;
471  };
472 
473 #ifndef DOXYGEN_SHOULD_SKIP_THIS
474 
475  // ===========================================================================
476  // === SCALAR IMPLEMENTATION OF PRIORITY QUEUES ===
477  // ===========================================================================
478 
479  /**
480  * @class PriorityQueueImplementation
481  * @headerfile priorityQueue.h <agrum/tools/core/priorityQueue.h>
482  * @ingroup priorityqueue_group
483  * @brief The internal class for representing priority queues for scalar
484  * Vals.
485  *
486  * Priority Queues have different implementations depending on the nature of
487  * the values they store. Basically, scalar values can lead to optimization
488  * of the code whereas general types like classes cannot. The current class
489  * is used for general types (and therefore for classes). The user shall not
490  * use directly the implementation but rather use the PriorityQueue class.
491  * The latter will be assigned the best implementation at compile time.
492  *
493  * @tparam Val The values type.
494  * @tparam Priority The priorities type.
495  * @tparam Cmp The priorities comparator.
496  * @tparam Alloc The values allocator.
497  * @tparam Gen Used for metaprogramation.
498  */
499  template < typename Val, typename Priority, typename Cmp, typename Alloc >
500  class PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true > {
501  /// All gum::PriorityQueue are friends with themselves.
502  friend class PriorityQueue< Val, Priority, Cmp, Alloc >;
503 
504  /// All gum::PriorityQueueImplementation are friends with themselves.
505  template < typename V, typename P, typename C, typename A, bool g >
506  friend class PriorityQueueImplementation;
507 
508  public:
509  /// Types for STL compliance.
510  /// @{
511  using value_type = Val;
512  using reference = Val&;
513  using const_reference = const Val&;
514  using pointer = Val*;
515  using const_pointer = const Val*;
516  using difference_type = std::ptrdiff_t;
517  using allocator_type = Alloc;
518  /// @}
519 
520  // The allocator for the indices.
521  using IndexAllocator =
522  typename Alloc::template rebind< std::pair< Val, Size > >::other;
523 
524  // The allocator for the heap.
525  using HeapAllocator =
526  typename Alloc::template rebind< std::pair< Priority, Val > >::other;
527 
528  private:
529  // ============================================================================
530  /// @name Constructors / Destructors
531  // ============================================================================
532  /// @{
533 
534  /**
535  * @brief Basic constructor. Creates an empty priority queue.
536  *
537  * @param compare A function taking two elements in argument, say e1 and
538  * e2, and returning a Boolean indicating wether e1 < e2, i.e., whether e1
539  * should be nearer than e2 to the top of the heap.
540  * @param capacity The size of the internal data structures containing the
541  * elements (could be for instance vectors or hashtables)
542  */
543  explicit PriorityQueueImplementation(Cmp compare, Size capacity);
544 
545  /**
546  * @brief Initializer list constructor.
547  *
548  * The elements of the initializer list are pairs <Val,Priority>. The
549  * comparison function is the default one, i.e., std::less<Priority>.
550  *
551  * @param list The initializer list.
552  */
553  explicit PriorityQueueImplementation(
554  std::initializer_list< std::pair< Val, Priority > > list);
555 
556  /**
557  * @brief Copy constructor.
558  * @param from The gum::PriorityQueueImplementation to copy.
559  */
560  PriorityQueueImplementation(
561  const PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >& from);
562 
563  /**
564  * @brief Generalized copy constructor.
565  * @tparam OtherAlloc The other gum::PriorityQueueImplementation allocator.
566  * @param from The gum::PriorityQueueImplementation to copy.
567  */
568  template < typename OtherAlloc >
569  PriorityQueueImplementation(
570  const PriorityQueueImplementation< Val, Priority, Cmp, OtherAlloc, true >&
571  from);
572 
573  /**
574  * @brief Move constructor.
575  * @param from The gum::PriorityQueueImplementation to move.
576  */
577  PriorityQueueImplementation(
578  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >&& from);
579 
580  /**
581  * @brief Class destructor.
582  */
583  ~PriorityQueueImplementation();
584 
585  /// @}
586 
587  public:
588  // ============================================================================
589  /// @name Operators
590  // ============================================================================
591  /// @{
592 
593  /**
594  * @brief Copy operator.
595  *
596  * When a problem occurs during the copy (for instance when not enough
597  * memory is available), the operator guarantees that the heap stays in a
598  * coherent state. Actually, the priority queue becomes empty. An exception
599  * is then thrown.
600  *
601  * @param from The gum::PriorityQueueImplementation to copy.
602  * @return Returns this gum::PriorityQueueImplementation.
603  */
604  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >& operator=(
605  const PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >& from);
606 
607  /**
608  * @brief Generalized copy operator.
609  *
610  * When a problem occurs during the copy (for instance when not enough
611  * memory is available), the operator guarantees that the heap stays in a
612  * coherent state. Actually, the priority queue becomes empty. An exception
613  * is then thrown.
614  *
615  * @tparam OtherAlloc The other gum::PriorityQueueImplementation allocator.
616  * @param from The gum::PriorityQueueImplementation to copy.
617  * @return Returns this gum::PriorityQueueImplementation.
618  */
619  template < typename OtherAlloc >
620  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >& operator=(
621  const PriorityQueueImplementation< Val, Priority, Cmp, OtherAlloc, true >&
622  from);
623 
624  /**
625  * @brief Move operator.
626  *
627  * @param from The gum::PriorityQueueImplementation to move.
628  * @return Returns this gum::PriorityQueueImplementation.
629  */
630  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >& operator=(
631  PriorityQueueImplementation< Val, Priority, Cmp, Alloc, true >&& from);
632 
633  /**
634  * @brief Returns the element at index "index_elt" from the priority queue.
635  * @param index_elt The index of the element to return.
636  * @return Returns the element at index "index_elt" from the priority
637  * queue.
638  * @throw NotFound Raised if the element does not exist.
639  */
640  const Val& operator[](Size index_elt) const;
641 
642  /// @}
643  // ============================================================================
644  /// @name Accessors / Modifiers
645  // ============================================================================
646  /// @{
647 
648  /**
649  * @brief Returns the number of elements in the priority queue.
650  * @return Returns the number of elements in the priority queue.
651  */
652  Size size() const noexcept;
653 
654  /**
655  * @brief Indicates whether the priority queue is empty.
656  * @return Returns true if the priority queue is empty.
657  */
658  bool empty() const noexcept;
659 
660  /**
661  * @brief Indicates whether the priority queue contains a given value.
662  * @param val The value to look for.
663  * @return Returns true if val is in the priority queue.
664  */
665  bool contains(Val val) const;
666 
667  /// returns the element at the top of the priority queue
668  /** @throw NotFound Raised if the queue is empty */
669  const Val& top() const;
670 
671  /**
672  * @brief Returns the priority of the top element.
673  * @return Returns the priority of the top element.
674  * @throw NotFound Raised if the queue is empty.
675  */
676  const Priority& topPriority() const;
677 
678  /**
679  * @brief Removes the top element from the priority queue and return it.
680  * @return Returns the top element from the priority queue.
681  * @throw NotFound Raised if the queue is empty.
682  */
683  Val pop();
684 
685  /**
686  * @brief Inserts a new (a copy) element in the priority queue.
687  *
688  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
689  * about the index.
690  *
691  * @param val The value to insert.
692  * @param priority The value's priority in the queue.
693  * @return Returns the index of the element inserted into the priority
694  * queue.
695  * @throw DuplicateElement Raised if the element already exists.
696  */
697  Size insert(Val val, const Priority& priority);
698 
699  /**
700  * @brief Inserts (by move) a new element in the priority queue.
701  *
702  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
703  * about the index.
704  *
705  * @param val The value to insert.
706  * @param priority The value's priority in the queue.
707  * @return Returns the index of the element inserted into the priority
708  * queue.
709  * @throw DuplicateElement Raised if the element already exists.
710  */
711  Size insert(Val val, Priority&& priority);
712 
713  /**
714  * @brief Emplace a new element into the priority queue.
715  *
716  * See gum::PriorityQueueImplementation::eraseByPos(Size) for more details
717  * about the index.
718  *
719  * @tparam Args The emplace arguments types.
720  * @param args The emplace arguments.
721  * @return Returns the index of the element inserted into the priority
722  * queue.
723  * @throw DuplicateElement Raised if the element already exists.
724  */
725  template < typename... Args >
726  Size emplace(Args&&... args);
727 
728  /**
729  * @brief Removes the top of the priority queue (but does not return it).
730  *
731  * If the heap is empty, it does nothing (in particular, it does not throw
732  * any exception).
733  */
734  void eraseTop();
735 
736  /**
737  * @brief Removes the element at position "index" from the priority queue.
738  *
739  * If the element cannot be found, the function returns without throwing
740  * any exception.
741  *
742  * The priority is computed as follows: suppose that the queue is a
743  * complete binary tree where all levels are completely filled except,
744  * eventually, the last one. In this case, the elements of the last
745  * level are all on the left of the tree.
746  *
747  * We assign 0 to the root, then parsing the tree from top to bottom then
748  * from left to right we increment the index and assigned it to the current
749  * node. Doing so, we get a unique index for each element. This is
750  * precisely what the index passed in argument of the function represents.
751  *
752  * @param index represents the position of the element to be removed.
753  */
754  void eraseByPos(Size index);
755 
756  /**
757  * @brief Removes a given element from the priority queue (but does not
758  * return it).
759  *
760  * If the element cannot be found, the function returns without throwing
761  * any exception.
762  *
763  * If the queue contains several times this element, then the one with the
764  * smallest index is removed.
765  *
766  * @param val the element we wish to remove.
767  */
768  void erase(Val val);
769 
770  /**
771  * @brief Modifies the priority of the element at position "index" of the
772  * queue.
773  *
774  * @param index The index of the element to update.
775  * @param new_priority The element's new priority.
776  * @return Returns the elements new priority.
777  * @throw NotFound Raised if the element cannot be found.
778  */
779  Size setPriorityByPos(Size index, const Priority& new_priority);
780 
781  /**
782  * @brief Modifies the priority of the element at position "index" of the
783  * queue.
784  *
785  * @param index The index of the element to update.
786  * @param new_priority The element's new priority.
787  * @return Returns the elements new priority.
788  * @throw NotFound Raised if the element cannot be found.
789  */
790  Size setPriorityByPos(Size index, Priority&& new_priority);
791 
792  /**
793  * @brief Modifies the priority of each instance of a given element.
794  * @param elt The value to update.
795  * @param new_priority The values new priority.
796  * @throw NotFound Raised if the element cannot be found.
797  */
798  void setPriority(Val elt, const Priority& new_priority);
799 
800  /**
801  * @brief Modifies the priority of each instance of a given element.
802  * @param elt The value to update.
803  * @param new_priority The values new priority.
804  * @throw NotFound Raised if the element cannot be found.
805  */
806  void setPriority(Val elt, Priority&& new_priority);
807 
808  /**
809  * @brief Returns the priority of an instance of the value passed in
810  * argument.
811  *
812  * @param elt The element for which the priority is returned.
813  * @return Returns the priority of an instance of the value passed in
814  * argument.
815  * @throw NotFound Raised if the element cannot be found.
816  */
817  const Priority& priority(Val elt) const;
818 
819  /**
820  * @brief Returns the priority of the value passed in argument.
821  * @param index The index of the value of which the priority is returned.
822  * @throw NotFound Raised if the element cannot be found.
823  */
824  const Priority& priorityByPos(Size index) const;
825 
826  /**
827  * @brief Removes all the elements from the queue.
828  */
829  void clear();
830 
831  /**
832  * @brief Returns a hashtable the keys of which are the values stored in
833  * the queue.
834  *
835  * The keys of the hashtable correspond to the values stored in the
836  * priority queue and, for each key, the corresponding value is the index
837  * in the queue where we can find the key.
838  *
839  * @return Returns a hashtable the keys of which are the values stored in
840  * the queue.
841  */
842  const HashTable< Val, Size >& allValues() const noexcept;
843 
844  /**
845  * @brief Displays the content of the queue.
846  * @return Returns the content of the queue.
847  */
848  std::string toString() const;
849 
850  /// @}
851  // ============================================================================
852  /// @name Fine tuning
853  // ============================================================================
854  /// @{
855 
856  /**
857  * @brief Returns the size of the internal structure storing the priority
858  * queue.
859  * @return Returns the size of the internal structure storing the priority
860  * queue.
861  */
862  Size capacity() const noexcept;
863 
864  /**
865  * @brief Changes the size of the internal structure storing the priority
866  * queue.
867  * @param new_size The internal structure new size.
868  */
869  void resize(Size new_size);
870 
871  /// @}
872 
873  private:
874  /// An array storing all the elements of the heap as well as their score.
875  std::vector< std::pair< Priority, Val >, HeapAllocator > heap__;
876 
877  /// A hashtable for quickly finding the elements by their value.
878  HashTable< Val, Size, IndexAllocator > indices__{HashTableConst::default_size,
879  true,
880  true};
881 
882  /// The number of elements in the heap.
883  Size nb_elements__{0};
884 
885  /// Comparison function.
886  Cmp cmp__;
887  };
888 
889 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
890 
891  // ===========================================================================
892  // === PRIORITY QUEUES ===
893  // ===========================================================================
894  /**
895  * @class PriorityQueue
896  * @headerfile priorityQueue.h <agrum/tools/core/priorityQueue.h>
897  * @brief A priorityQueue is a heap in which each element has a mutable
898  * priority
899  * @ingroup basicstruct_group
900  * @ingroup priorityqueue_group
901  *
902  * A priority queue is quite similar to a heap except that a priority (a
903  * score) is assigned to each element in the structure. The elements are
904  * sorted according to a weak order on the scores. The priority of any
905  * element can be changed at any moment by the user. The priority queue then
906  * restores a heap property accordingly. Duplicate elements are not allowed
907  * in priority queues; if you wish an element to appear several times with
908  * different priorities, prefer using class MultiplePriorityQueue.
909  *
910  * @par Usage example:
911  * @code
912  * // create a priority queue of strings, the priorities of which are integers
913  * // the element at the top of the queue has the smallest priority
914  * PriorityQueue<std::string> queue1;
915  *
916  * // insert elements into the queue
917  * queue1.insert ("AAA", 8);
918  * queue1.insert ("BBB", 10);
919  * queue1.insert ("CCC", 2);
920  * queue1.insert ("DDD", 23);
921  * queue1.insert ("EEE", 24);
922  *
923  * // copy the queue
924  * PriorityQueue<std::string> queue2 = queue1;
925  *
926  * // initializer list constructor
927  * PriorityQueue<std::string,int> queue3 { std::pair<std::string,int>("aa",3),
928  * std::pair<std::string,int>("bb",2)
929  * };
930  *
931  * // create a priority queue of strings, the priorities of which are
932  * // pairs of ints
933  * PriorityQueue< std::string, std::pair<int,int> > queue3;
934  *
935  * // get the top element, then remove it
936  * std::cerr << queue2.top() << std::endl;
937  * queue2.eraseTop();
938  *
939  * // get the top element, then remove it
940  * std::cerr << queue2.pop() << std::endl;
941  *
942  * // output the content of the queue
943  * std::cerr << queue1 << std::endl;
944  *
945  * // change the priority of the element at position 3
946  * Size new_pos=queue1.setPriorityByPos (3,100);
947  *
948  * // change the priority of all instances of element "AAA"
949  * queue1.setPriority ("AAA",100);
950  * @endcode
951  *
952  * @tparam Val The values type.
953  * @tparam Priority The priorities type.
954  * @tparam Cmp The priorities comparator.
955  * @tparam Alloc The values allocator.
956  */
957  template < typename Val,
958  typename Priority = int,
959  typename Cmp = std::less< Priority >,
960  typename Alloc = std::allocator< Val > >
961  class PriorityQueue:
962  public PriorityQueueImplementation< Val,
963  Priority,
964  Cmp,
965  Alloc,
966  std::is_scalar< Val >::value > {
967  public:
968  /// Types for STL compliance.
969  /// @{
970  using value_type = Val;
971  using reference = Val&;
972  using const_reference = const Val&;
973  using pointer = Val*;
974  using const_pointer = const Val*;
975  using difference_type = std::ptrdiff_t;
976  using allocator_type = Alloc;
977  /// @}
978 
979  using Implementation
980  = PriorityQueueImplementation< Val,
981  Priority,
982  Cmp,
983  Alloc,
984  std::is_scalar< Val >::value >;
985 
986  // ============================================================================
987  /// @name Constructors / Destructors
988  // ============================================================================
989  /// @{
990 
991  /**
992  * @brief Basic constructor. Creates an empty priority queue.
993  *
994  * @param compare a function taking two elements in argument, say e1 and
995  * e2, and returning a Boolean indicating wether e1 < e2, i.e., whether e1
996  * should be nearer than e2 to the top of the heap.
997  * @param capacity the size of the internal data structures containing the
998  * elements (could be for instance vectors or hashtables).
999  */
1000  explicit PriorityQueue(Cmp compare = Cmp(),
1001  Size capacity = GUM_PRIORITY_QUEUE_DEFAULT_CAPACITY);
1002 
1003  /**
1004  * @brief Initializer list constructor.
1005  *
1006  * The elements of the initializer list are pairs <Val,Priority>.
1007  * The comparison function is the default one, i.e., std::less<Priority>.
1008  *
1009  * @param list The initializer list.
1010  */
1011  explicit PriorityQueue(
1012  std::initializer_list< std::pair< Val, Priority > > list);
1013 
1014  /**
1015  * @brief Copy constructor.
1016  * @param from The gum::PriorityQueue to copy.
1017  */
1018  PriorityQueue(const PriorityQueue< Val, Priority, Cmp, Alloc >& from);
1019 
1020  /**
1021  * @brief Generalized copy constructor.
1022  * @param from The gum::PriorityQueue to copy.
1023  */
1024  template < typename OtherAlloc >
1025  PriorityQueue(const PriorityQueue< Val, Priority, Cmp, OtherAlloc >& from);
1026 
1027  /**
1028  * @brief Move constructor.
1029  * @param from The gum::PriorityQueue to move.
1030  */
1031  PriorityQueue(PriorityQueue< Val, Priority, Cmp, Alloc >&& from);
1032 
1033  /**
1034  * Class destructor.
1035  */
1036  ~PriorityQueue();
1037 
1038  /// @}
1039  // ============================================================================
1040  /// @name Operators
1041  // ============================================================================
1042  /// @{
1043 
1044  /**
1045  * @brief Copy operator.
1046  *
1047  * When a problem occurs during the copy (for instance when not enough
1048  * memory is available), the operator guarantees that the heap stays in a
1049  * coherent state. Actually, the priority queue becomes empty. An exception
1050  * is then thrown.
1051  *
1052  * @param from The gum::PriorityQueue to copy.
1053  * @return Returns this gum::PriorityQueue.
1054  */
1055  PriorityQueue< Val, Priority, Cmp, Alloc >&
1056  operator=(const PriorityQueue< Val, Priority, Cmp, Alloc >& from);
1057 
1058  /**
1059  * @brief Generalized opy operator.
1060  *
1061  * When a problem occurs during the copy (for instance when not enough
1062  * memory is available), the operator guarantees that the heap stays in a
1063  * coherent state. Actually, the priority queue becomes empty. An exception
1064  * is then thrown.
1065  *
1066  * @param from The gum::PriorityQueue to copy.
1067  * @return Returns this gum::PriorityQueue.
1068  */
1069  template < typename OtherAlloc >
1070  PriorityQueue< Val, Priority, Cmp, Alloc >&
1071  operator=(const PriorityQueue< Val, Priority, Cmp, OtherAlloc >& from);
1072 
1073  /**
1074  * @brief Move operator.
1075  * @param from The gum::PriorityQueue to move.
1076  * @return Returns this gum::PriorityQueue.
1077  */
1078  PriorityQueue< Val, Priority, Cmp, Alloc >&
1079  operator=(PriorityQueue< Val, Priority, Cmp, Alloc >&& from);
1080 
1081  /// @}
1082  };
1083 
1084 } /* namespace gum */
1085 
1086 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
1087 # ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
1088 extern template class gum::PriorityQueue< std::string >;
1089 # endif
1090 #endif
1091 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
1092 # ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
1093 extern template class gum::PriorityQueue< int, int >;
1094 # endif
1095 #endif
1096 
1097 // always include the implementation of the templates
1098 #include <agrum/tools/core/priorityQueue_tpl.h>
1099 
1100 #endif /* GUM_PRIORITY_QUEUE_H */
#define GUM_PRIORITY_QUEUE_DEFAULT_CAPACITY
Definition: priorityQueue.h:46