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