aGrUM  0.16.0
priorityQueue_tpl.h
Go to the documentation of this file.
1 
31 
32 namespace gum {
33 
34  // ===========================================================================
35  // === GENERAL IMPLEMENTATIION OF PRIORITY QUEUES ===
36  // ===========================================================================
37 
38  // basic constructor
39  template < typename Val,
40  typename Priority,
41  typename Cmp,
42  typename Alloc,
43  bool Gen >
45  PriorityQueueImplementation(Cmp compare, Size capacity) :
46  __indices(capacity >> 1, true, true),
47  __cmp(compare) {
48  __heap.reserve(capacity);
49 
50  // for debugging purposes
51  GUM_CONSTRUCTOR(PriorityQueueImplementation);
52  }
53 
54  // initializer list constructor
55  template < typename Val,
56  typename Priority,
57  typename Cmp,
58  typename Alloc,
59  bool Gen >
62  std::initializer_list< std::pair< Val, Priority > > list) :
63  __indices(Size(list.size()) / 2, true, true) {
64  // fill the queue
65  __heap.reserve(list.size());
66  for (const auto& elt : list) {
67  insert(elt.first, elt.second);
68  }
69 
70  // for debugging purposes
71  GUM_CONSTRUCTOR(PriorityQueueImplementation);
72  }
73 
74  // copy constructor
75  template < typename Val,
76  typename Priority,
77  typename Cmp,
78  typename Alloc,
79  bool Gen >
83  from) :
84  __heap(from.__heap),
85  __indices(from.__indices), __nb_elements(from.__nb_elements),
86  __cmp(from.__cmp) {
87  // fill the heap structure
88  for (const auto& elt : __indices) {
89  __heap[elt.second].second = &(elt.first);
90  }
91 
92  // for debugging purposes
93  GUM_CONS_CPY(PriorityQueueImplementation);
94  }
95 
96  // generalized copy constructor
97  template < typename Val,
98  typename Priority,
99  typename Cmp,
100  typename Alloc,
101  bool Gen >
102  template < typename OtherAlloc >
106  from) :
107  __indices(from.__indices),
108  __nb_elements(from.__nb_elements), __cmp(from.__cmp) {
109  // fill the heap structure
110  if (__nb_elements) {
111  __heap.reserve(from.__heap.size());
112  for (const auto& elt : from.__heap) {
113  __heap.push_back(elt);
114  }
115  for (const auto& elt : __indices) {
116  __heap[elt.second].second = &(elt.first);
117  }
118  }
119 
120  // for debugging purposes
121  GUM_CONS_CPY(PriorityQueueImplementation);
122  }
123 
124  // move constructor
125  template < typename Val,
126  typename Priority,
127  typename Cmp,
128  typename Alloc,
129  bool Gen >
133  __heap(std::move(from.__heap)),
134  __indices(std::move(from.__indices)),
135  __nb_elements(std::move(from.__nb_elements)), __cmp(std::move(from.__cmp)) {
136  // for debugging purposes
137  GUM_CONS_MOV(PriorityQueueImplementation);
138  }
139 
140  // destructor
141  template < typename Val,
142  typename Priority,
143  typename Cmp,
144  typename Alloc,
145  bool Gen >
148  // for debugging purposes
149  GUM_DESTRUCTOR(PriorityQueueImplementation);
150  }
151 
152  // copy operator
153  template < typename Val,
154  typename Priority,
155  typename Cmp,
156  typename Alloc,
157  bool Gen >
161  from) {
162  // avoid self assignment
163  if (this != &from) {
164  // for debugging purposes
165  GUM_OP_CPY(PriorityQueueImplementation);
166 
167  try {
168  // set the comparison function
169  __cmp = from.__cmp;
170 
171  // copy the indices and the heap
172  __indices = from.__indices;
173  __heap = from.__heap;
174  __nb_elements = from.__nb_elements;
175 
176  // restore the link between __indices and __heap
177  for (const auto& elt : __indices) {
178  __heap[elt.second].second = &(elt.first);
179  }
180  } catch (...) {
181  __heap.clear();
182  __indices.clear();
183  __nb_elements = 0;
184 
185  throw;
186  }
187  }
188 
189  return *this;
190  }
191 
192  // generalized copy operator
193  template < typename Val,
194  typename Priority,
195  typename Cmp,
196  typename Alloc,
197  bool Gen >
198  template < typename OtherAlloc >
202  from) {
203  // for debugging purposes
204  GUM_OP_CPY(PriorityQueueImplementation);
205 
206  try {
207  // set the comprison function
208  __cmp = from.__cmp;
209 
210  // copy the indices and the heap
211  __indices = from.__indices;
212  __nb_elements = from.__nb_elements;
213 
214  __heap.clear();
215  if (__nb_elements) {
216  __heap.reserve(from.__heap.size());
217  for (const auto& elt : from.__heap) {
218  __heap.push_back(elt);
219  }
220  for (const auto& elt : __indices) {
221  __heap[elt.second].second = &(elt.first);
222  }
223  }
224  } catch (...) {
225  __heap.clear();
226  __indices.clear();
227  __nb_elements = 0;
228 
229  throw;
230  }
231 
232  return *this;
233  }
234 
235  // move operator
236  template < typename Val,
237  typename Priority,
238  typename Cmp,
239  typename Alloc,
240  bool Gen >
244  // avoid self assignment
245  if (this != &from) {
246  // for debugging purposes
247  GUM_OP_MOV(PriorityQueueImplementation);
248 
249  __indices = std::move(from.__indices);
250  __heap = std::move(from.__heap);
251  __cmp = std::move(from.__cmp);
252  __nb_elements = std::move(from.__nb_elements);
253  }
254 
255  return *this;
256  }
257 
258  // returns the element at the top of the priority queue
259  template < typename Val,
260  typename Priority,
261  typename Cmp,
262  typename Alloc,
263  bool Gen >
264  INLINE const Val&
266  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
267 
268  return *(__heap[0].second);
269  }
270 
271  // returns the priority of the top element
272  template < typename Val,
273  typename Priority,
274  typename Cmp,
275  typename Alloc,
276  bool Gen >
277  INLINE const Priority&
279  const {
280  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
281 
282  return __heap[0].first;
283  }
284 
285  // returns the number of elements in the priority queue
286  template < typename Val,
287  typename Priority,
288  typename Cmp,
289  typename Alloc,
290  bool Gen >
291  INLINE Size
293  noexcept {
294  return __nb_elements;
295  }
296 
297  // return the size of the array storing the priority queue
298  template < typename Val,
299  typename Priority,
300  typename Cmp,
301  typename Alloc,
302  bool Gen >
303  INLINE Size
305  const noexcept {
306  return Size(__heap.capacity());
307  }
308 
309  // changes the size of the array storing the priority queue
310  template < typename Val,
311  typename Priority,
312  typename Cmp,
313  typename Alloc,
314  bool Gen >
315  INLINE void
317  Size new_size) {
318  if (new_size < __nb_elements) return;
319 
320  __heap.reserve(new_size);
321  __indices.resize(new_size / 2);
322  }
323 
324  // removes all the elements from the queue
325  template < typename Val,
326  typename Priority,
327  typename Cmp,
328  typename Alloc,
329  bool Gen >
330  INLINE void
332  __nb_elements = 0;
333  __heap.clear();
334  __indices.clear();
335  }
336 
337  // removes the element at index elt from the priority queue
338  template < typename Val,
339  typename Priority,
340  typename Cmp,
341  typename Alloc,
342  bool Gen >
344  Size index) {
345  if (index >= __nb_elements) return;
346 
347  // remove the element from the hashtable
348  __indices.erase(*(__heap[index].second));
349 
350  // put the last element at the "index" location
351  std::pair< Priority, const Val* > last = std::move(__heap[__nb_elements - 1]);
352  __heap.pop_back();
353  --__nb_elements;
354 
355  if (!__nb_elements || (index == __nb_elements)) return;
356 
357  // restore the heap property
358  Size i = index;
359 
360  for (Size j = (index << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
361  // let j be the max child
362  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
363  ++j;
364 
365  // if "last" is lower than heap[j], "last" must be stored at index i
366  if (__cmp(last.first, __heap[j].first)) break;
367 
368  // else pull up the jth node
369  __heap[i] = std::move(__heap[j]);
370  __indices[*(__heap[i].second)] = i;
371  }
372 
373  // put "last" back into the heap
374  __heap[i] = std::move(last);
375  __indices[*(__heap[i].second)] = i;
376  }
377 
378  // removes a given element from the priority queue (but does not return it)
379  template < typename Val,
380  typename Priority,
381  typename Cmp,
382  typename Alloc,
383  bool Gen >
385  const Val& val) {
386  try {
387  eraseByPos(__indices[val]);
388  } catch (NotFound&) {}
389  }
390 
391  // removes the top of the priority queue (but does not return it)
392  template < typename Val,
393  typename Priority,
394  typename Cmp,
395  typename Alloc,
396  bool Gen >
397  INLINE void
399  eraseByPos(0);
400  }
401 
402  // removes the top element from the priority queue and return it
403  template < typename Val,
404  typename Priority,
405  typename Cmp,
406  typename Alloc,
407  bool Gen >
409  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
410 
411  Val v = *(__heap[0].second);
412  eraseByPos(0);
413 
414  return v;
415  }
416 
417  // returns a hashtable the keys of which are the values stored in the queue
418  template < typename Val,
419  typename Priority,
420  typename Cmp,
421  typename Alloc,
422  bool Gen >
423  INLINE const HashTable< Val, Size >&
425  const noexcept {
426  return reinterpret_cast< const HashTable< Val, Size >& >(__indices);
427  }
428 
429  // inserts a new (a copy) element in the priority queue
430  template < typename Val,
431  typename Priority,
432  typename Cmp,
433  typename Alloc,
434  bool Gen >
435  INLINE Size
437  const Val& val, const Priority& priority) {
438  // create the entry in the indices hashtable (if the element already exists,
439  // __indices.insert will raise a Duplicateelement exception)
441  __indices.insert(val, 0);
442 
443  try {
444  __heap.push_back(
445  std::pair< Priority, const Val* >(priority, &new_elt.first));
446  } catch (...) {
447  __indices.erase(val);
448  throw;
449  }
450 
451  std::pair< Priority, const Val* > new_heap_val =
452  std::move(__heap[__nb_elements]);
453  ++__nb_elements;
454 
455  // restore the heap property
456  Size i = __nb_elements - 1;
457 
458  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
459  i = j, j = (j - 1) >> 1) {
460  __heap[i] = std::move(__heap[j]);
461  __indices[*(__heap[i].second)] = i;
462  }
463 
464  // put the new bucket into the heap
465  __heap[i].first = std::move(new_heap_val.first);
466  __heap[i].second = &(new_elt.first);
467  new_elt.second = i;
468 
469  return i;
470  }
471 
472  // inserts by move a new element in the priority queue
473  template < typename Val,
474  typename Priority,
475  typename Cmp,
476  typename Alloc,
477  bool Gen >
478  INLINE Size
480  Val&& val, Priority&& priority) {
481  // create the entry in the indices hashtable (if the element already exists,
482  // __indices.insert will raise a Duplicateelement exception)
484  __indices.insert(std::move(val), 0);
485 
486  try {
487  __heap.push_back(
488  std::pair< Priority, const Val* >(std::move(priority), &(new_elt.first)));
489  } catch (...) {
490  __indices.erase(new_elt.first);
491  throw;
492  }
493 
494  std::pair< Priority, const Val* > new_heap_val =
495  std::move(__heap[__nb_elements]);
496  ++__nb_elements;
497 
498  // restore the heap property
499  Size i = __nb_elements - 1;
500 
501  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
502  i = j, j = (j - 1) >> 1) {
503  __heap[i] = std::move(__heap[j]);
504  __indices[*(__heap[i].second)] = i;
505  }
506 
507  // put the new bucket into the heap
508  __heap[i].first = std::move(new_heap_val.first);
509  __heap[i].second = &(new_elt.first);
510  new_elt.second = i;
511 
512  return i;
513  }
514 
515  // emplace a new element into the priority queue
516  template < typename Val,
517  typename Priority,
518  typename Cmp,
519  typename Alloc,
520  bool Gen >
521  template < typename... Args >
522  INLINE Size
524  Args&&... args) {
525  std::pair< Val, Priority > new_elt =
526  std::make_pair< Val, Priority >(std::forward< Args >(args)...);
527  return insert(std::move(new_elt.first), std::move(new_elt.second));
528  }
529 
530  // indicates whether the priority queue is empty
531  template < typename Val,
532  typename Priority,
533  typename Cmp,
534  typename Alloc,
535  bool Gen >
536  INLINE bool
538  noexcept {
539  return (__nb_elements == 0);
540  }
541 
542  // indicates whether the priority queue contains a given value
543  template < typename Val,
544  typename Priority,
545  typename Cmp,
546  typename Alloc,
547  bool Gen >
548  INLINE bool
550  const Val& val) const {
551  return __indices.exists(val);
552  }
553 
554  // returns the element at position "index" in the priority queue
555  template < typename Val,
556  typename Priority,
557  typename Cmp,
558  typename Alloc,
559  bool Gen >
561  operator[](Size index) const {
562  if (index >= __nb_elements) {
564  "not enough elements in the PriorityQueueImplementation");
565  }
566 
567  return *(__heap[index].second);
568  }
569 
570  // displays the content of the queue
571  template < typename Val,
572  typename Priority,
573  typename Cmp,
574  typename Alloc,
575  bool Gen >
576  std::string
578  const {
579  bool deja = false;
580  std::stringstream stream;
581  stream << "[";
582 
583  for (Size i = 0; i != __nb_elements; ++i, deja = true) {
584  if (deja) stream << " , ";
585 
586  stream << "(" << __heap[i].first << " , " << *(__heap[i].second) << ")";
587  }
588 
589  stream << "]";
590 
591  return stream.str();
592  }
593 
594  // changes the size of the internal structure storing the priority queue
595  template < typename Val,
596  typename Priority,
597  typename Cmp,
598  typename Alloc,
599  bool Gen >
601  setPriorityByPos(Size index, const Priority& new_priority) {
602  // check whether the element the priority of which should be changed exists
603  if (index >= __nb_elements) {
605  "not enough elements in the PriorityQueueImplementation");
606  }
607 
608  // get the element itself
609  const Val* val = __heap[index].second;
610 
611  // restore the heap property
612  Size i = index;
613 
614  // move val upward if needed
615  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
616  i = j, j = (j - 1) >> 1) {
617  __heap[i] = std::move(__heap[j]);
618  __indices[*(__heap[i].second)] = i;
619  }
620 
621  // move val downward if needed
622  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
623  // let j be the max child
624  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
625  ++j;
626 
627  // if "val" is lower than heap[j], "val" must be stored at index i
628  if (__cmp(new_priority, __heap[j].first)) break;
629 
630  // else pull up the jth node
631  __heap[i] = std::move(__heap[j]);
632  __indices[*(__heap[i].second)] = i;
633  }
634 
635  // update the index of val
636  __heap[i].first = new_priority;
637  __heap[i].second = val;
638  __indices[*val] = i;
639 
640  return i;
641  }
642 
643  // changes the size of the internal structure storing the priority queue
644  template < typename Val,
645  typename Priority,
646  typename Cmp,
647  typename Alloc,
648  bool Gen >
650  setPriorityByPos(Size index, Priority&& new_priority) {
651  // check whether the element the priority of which should be changed exists
652  if (index >= __nb_elements) {
654  "not enough elements in the PriorityQueueImplementation");
655  }
656 
657  // get the element itself
658  const Val* val = __heap[index].second;
659 
660  // restore the heap property
661  Size i = index;
662 
663  // move val upward if needed
664  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
665  i = j, j = (j - 1) >> 1) {
666  __heap[i] = std::move(__heap[j]);
667  __indices[*(__heap[i].second)] = i;
668  }
669 
670  // move val downward if needed
671  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
672  // let j be the max child
673  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
674  ++j;
675 
676  // if "val" is lower than heap[j], "val" must be stored at index i
677  if (__cmp(new_priority, __heap[j].first)) break;
678 
679  // else pull up the jth node
680  __heap[i] = std::move(__heap[j]);
681  __indices[*(__heap[i].second)] = i;
682  }
683 
684  // update the index of val
685  __heap[i].first = std::move(new_priority);
686  __heap[i].second = val;
687  __indices[*val] = i;
688 
689  return i;
690  }
691 
692  // modifies the priority of a given element
693  template < typename Val,
694  typename Priority,
695  typename Cmp,
696  typename Alloc,
697  bool Gen >
699  const Val& elt, const Priority& new_priority) {
700  setPriorityByPos(__indices[elt], new_priority);
701  }
702 
703  // modifies the priority of a given element
704  template < typename Val,
705  typename Priority,
706  typename Cmp,
707  typename Alloc,
708  bool Gen >
710  const Val& elt, Priority&& new_priority) {
711  setPriorityByPos(__indices[elt], std::move(new_priority));
712  }
713 
714  // returns the priority of a given element
715  template < typename Val,
716  typename Priority,
717  typename Cmp,
718  typename Alloc,
719  bool Gen >
720  INLINE const Priority&
722  const Val& elt) const {
723  return __heap[__indices[elt]].first;
724  }
725 
726  // returns the priority of a given element
727  template < typename Val,
728  typename Priority,
729  typename Cmp,
730  typename Alloc,
731  bool Gen >
732  INLINE const Priority&
734  Size index) const {
735  if (index > __nb_elements) {
737  "not enough elements in the PriorityQueueImplementation");
738  }
739  return __heap[index].first;
740  }
741 
742  // ===========================================================================
743  // === SCALAR OPTIMIZED IMPLEMENTATION OF PRIORITY QUEUES ===
744  // ===========================================================================
745 
746  // basic constructor
747  template < typename Val, typename Priority, typename Cmp, typename Alloc >
749  PriorityQueueImplementation(Cmp compare, Size capacity) :
750  __indices(capacity >> 1, true, true),
751  __cmp(compare) {
752  __heap.reserve(capacity);
753 
754  // for debugging purposes
755  GUM_CONSTRUCTOR(PriorityQueueImplementation);
756  }
757 
758  // initializer list constructor
759  template < typename Val, typename Priority, typename Cmp, typename Alloc >
762  std::initializer_list< std::pair< Val, Priority > > list) :
763  __indices(Size(list.size()) / 2, true, true) {
764  // fill the queue
765  __heap.reserve(list.size());
766  for (const auto& elt : list) {
767  insert(elt.first, elt.second);
768  }
769 
770  // for debugging purposes
771  GUM_CONSTRUCTOR(PriorityQueueImplementation);
772  }
773 
774  // copy constructor
775  template < typename Val, typename Priority, typename Cmp, typename Alloc >
779  from) :
780  __heap(from.__heap),
781  __indices(from.__indices), __nb_elements(from.__nb_elements),
782  __cmp(from.__cmp) {
783  // for debugging purposes
784  GUM_CONS_CPY(PriorityQueueImplementation);
785  }
786 
787  // generalized copy constructor
788  template < typename Val, typename Priority, typename Cmp, typename Alloc >
789  template < typename OtherAlloc >
793  from) :
794  __indices(from.__indices),
795  __nb_elements(from.__nb_elements), __cmp(from.__cmp) {
796  // fill the heap structure
797  if (__nb_elements) {
798  __heap.reserve(from.__heap.size());
799  for (const auto& elt : from.__heap) {
800  __heap.push_back(elt);
801  }
802  }
803 
804  // for debugging purposes
805  GUM_CONS_CPY(PriorityQueueImplementation);
806  }
807 
808  // move constructor
809  template < typename Val, typename Priority, typename Cmp, typename Alloc >
813  __heap(std::move(from.__heap)),
814  __indices(std::move(from.__indices)),
815  __nb_elements(std::move(from.__nb_elements)), __cmp(std::move(from.__cmp)) {
816  // for debugging purposes
817  GUM_CONS_MOV(PriorityQueueImplementation);
818  }
819 
820  // destructor
821  template < typename Val, typename Priority, typename Cmp, typename Alloc >
824  // for debugging purposes
825  GUM_DESTRUCTOR(PriorityQueueImplementation);
826  }
827 
828  // copy operator
829  template < typename Val, typename Priority, typename Cmp, typename Alloc >
833  from) {
834  // avoid self assignment
835  if (this != &from) {
836  // for debugging purposes
837  GUM_OP_CPY(PriorityQueueImplementation);
838 
839  try {
840  // set the comparison function
841  __cmp = from.__cmp;
842 
843  // copy the indices and the heap
844  __indices = from.__indices;
845  __heap = from.__heap;
846  __nb_elements = from.__nb_elements;
847  } catch (...) {
848  __heap.clear();
849  __indices.clear();
850  __nb_elements = 0;
851 
852  throw;
853  }
854  }
855 
856  return *this;
857  }
858 
859  // generalized copy operator
860  template < typename Val, typename Priority, typename Cmp, typename Alloc >
861  template < typename OtherAlloc >
865  from) {
866  // for debugging purposes
867  GUM_OP_CPY(PriorityQueueImplementation);
868 
869  try {
870  // set the comprison function
871  __cmp = from.__cmp;
872 
873  // copy the indices and the heap
874  __indices = from.__indices;
875  __nb_elements = from.__nb_elements;
876 
877  __heap.clear();
878  if (__nb_elements) {
879  __heap.reserve(from.__heap.size());
880  for (const auto& elt : from.__heap) {
881  __heap.push_back(elt);
882  }
883  }
884  } catch (...) {
885  __heap.clear();
886  __indices.clear();
887  __nb_elements = 0;
888 
889  throw;
890  }
891 
892  return *this;
893  }
894 
895  // move operator
896  template < typename Val, typename Priority, typename Cmp, typename Alloc >
900  // avoid self assignment
901  if (this != &from) {
902  // for debugging purposes
903  GUM_OP_MOV(PriorityQueueImplementation);
904 
905  __indices = std::move(from.__indices);
906  __heap = std::move(from.__heap);
907  __cmp = std::move(from.__cmp);
908  __nb_elements = std::move(from.__nb_elements);
909  }
910 
911  return *this;
912  }
913 
914  // returns the element at the top of the priority queue
915  template < typename Val, typename Priority, typename Cmp, typename Alloc >
916  INLINE const Val&
918  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
919 
920  return __heap[0].second;
921  }
922 
923  // returns the priority of the top element
924  template < typename Val, typename Priority, typename Cmp, typename Alloc >
925  INLINE const Priority&
927  const {
928  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
929 
930  return __heap[0].first;
931  }
932 
933  // returns the number of elements in the priority queue
934  template < typename Val, typename Priority, typename Cmp, typename Alloc >
935  INLINE Size
937  noexcept {
938  return __nb_elements;
939  }
940 
941  // return the size of the array storing the priority queue
942  template < typename Val, typename Priority, typename Cmp, typename Alloc >
943  INLINE Size
945  const noexcept {
946  return Size(__heap.capacity());
947  }
948 
949  // changes the size of the array storing the priority queue
950  template < typename Val, typename Priority, typename Cmp, typename Alloc >
951  INLINE void
953  Size new_size) {
954  if (new_size < __nb_elements) return;
955 
956  __heap.reserve(new_size);
957  __indices.resize(new_size / 2);
958  }
959 
960  // removes all the elements from the queue
961  template < typename Val, typename Priority, typename Cmp, typename Alloc >
962  INLINE void
964  __nb_elements = 0;
965  __heap.clear();
966  __indices.clear();
967  }
968 
969  // removes the element at index elt from the priority queue
970  template < typename Val, typename Priority, typename Cmp, typename Alloc >
972  Size index) {
973  if (index >= __nb_elements) return;
974 
975  // remove the element from the hashtable
976  __indices.erase(__heap[index].second);
977 
978  // put the last element at the "index" location
979  std::pair< Priority, Val > last = std::move(__heap[__nb_elements - 1]);
980  __heap.pop_back();
981  --__nb_elements;
982 
983  if (!__nb_elements || (index == __nb_elements)) return;
984 
985  // restore the heap property
986  Size i = index;
987 
988  for (Size j = (index << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
989  // let j be the max child
990  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
991  ++j;
992 
993  // if "last" is lower than heap[j], "last" must be stored at index i
994  if (__cmp(last.first, __heap[j].first)) break;
995 
996  // else pull up the jth node
997  __heap[i] = std::move(__heap[j]);
998  __indices[__heap[i].second] = i;
999  }
1000 
1001  // put "last" back into the heap
1002  __heap[i] = std::move(last);
1003  __indices[__heap[i].second] = i;
1004  }
1005 
1006  // removes a given element from the priority queue (but does not return it)
1007  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1008  INLINE void
1010  Val val) {
1011  try {
1012  eraseByPos(__indices[val]);
1013  } catch (NotFound&) {}
1014  }
1015 
1016  // removes the top of the priority queue (but does not return it)
1017  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1018  INLINE void
1020  eraseByPos(0);
1021  }
1022 
1023  // removes the top element from the priority queue and return it
1024  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1025  INLINE Val
1027  if (!__nb_elements) { GUM_ERROR(NotFound, "empty priority queue"); }
1028 
1029  Val v = __heap[0].second;
1030  eraseByPos(0);
1031 
1032  return v;
1033  }
1034 
1035  // returns a hashtable the keys of which are the values stored in the queue
1036  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1037  INLINE const HashTable< Val, Size >&
1039  const noexcept {
1040  return reinterpret_cast< const HashTable< Val, Size >& >(__indices);
1041  }
1042 
1043  // inserts a new (a copy) element in the priority queue
1044  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1045  INLINE Size
1047  Val val, const Priority& priority) {
1048  // create the entry in the indices hashtable (if the element already exists,
1049  // __indices.insert will raise a Duplicateelement exception)
1051  __indices.insert(val, 0);
1052 
1053  try {
1054  __heap.push_back(std::pair< Priority, Val >(priority, val));
1055  } catch (...) {
1056  __indices.erase(val);
1057  throw;
1058  }
1059 
1060  std::pair< Priority, Val > new_heap_val = std::move(__heap[__nb_elements]);
1061  ++__nb_elements;
1062 
1063  // restore the heap property
1064  Size i = __nb_elements - 1;
1065 
1066  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
1067  i = j, j = (j - 1) >> 1) {
1068  __heap[i] = std::move(__heap[j]);
1069  __indices[__heap[i].second] = i;
1070  }
1071 
1072  // put the new bucket into the heap
1073  __heap[i].first = std::move(new_heap_val.first);
1074  __heap[i].second = val;
1075  new_elt.second = i;
1076 
1077  return i;
1078  }
1079 
1080  // inserts by move a new element in the priority queue
1081  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1082  INLINE Size
1084  Val val, Priority&& priority) {
1085  // create the entry in the indices hashtable (if the element already exists,
1086  // __indices.insert will raise a Duplicateelement exception)
1088  __indices.insert(val, 0);
1089 
1090  try {
1091  __heap.push_back(std::pair< Priority, Val >(std::move(priority), val));
1092  } catch (...) {
1093  __indices.erase(val);
1094  throw;
1095  }
1096 
1097  std::pair< Priority, Val > new_heap_val = std::move(__heap[__nb_elements]);
1098  ++__nb_elements;
1099 
1100  // restore the heap property
1101  Size i = __nb_elements - 1;
1102 
1103  for (Size j = (i - 1) >> 1; i && __cmp(new_heap_val.first, __heap[j].first);
1104  i = j, j = (j - 1) >> 1) {
1105  __heap[i] = std::move(__heap[j]);
1106  __indices[__heap[i].second] = i;
1107  }
1108 
1109  // put the new bucket into the heap
1110  __heap[i].first = std::move(new_heap_val.first);
1111  __heap[i].second = val;
1112  new_elt.second = i;
1113 
1114  return i;
1115  }
1116 
1117  // emplace a new element into the priority queue
1118  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1119  template < typename... Args >
1120  INLINE Size
1122  Args&&... args) {
1123  std::pair< Val, Priority > new_elt =
1124  std::make_pair< Val, Priority >(std::forward< Args >(args)...);
1125  return insert(new_elt.first, std::move(new_elt.second));
1126  }
1127 
1128  // indicates whether the priority queue is empty
1129  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1130  INLINE bool
1132  noexcept {
1133  return (__nb_elements == 0);
1134  }
1135 
1136  // indicates whether the priority queue contains a given value
1137  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1138  INLINE bool
1140  Val val) const {
1141  return __indices.exists(val);
1142  }
1143 
1144  // returns the element at position "index" in the priority queue
1145  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1146  INLINE const Val&
1148  operator[](Size index) const {
1149  if (index >= __nb_elements) {
1151  "not enough elements in the PriorityQueueImplementation");
1152  }
1153 
1154  return __heap[index].second;
1155  }
1156 
1157  // displays the content of the queue
1158  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1159  std::string
1161  const {
1162  bool deja = false;
1163  std::stringstream stream;
1164  stream << "[";
1165 
1166  for (Size i = 0; i != __nb_elements; ++i, deja = true) {
1167  if (deja) stream << " , ";
1168 
1169  stream << "(" << __heap[i].first << " , " << __heap[i].second << ")";
1170  }
1171 
1172  stream << "]";
1173 
1174  return stream.str();
1175  }
1176 
1177  // changes the size of the internal structure storing the priority queue
1178  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1180  setPriorityByPos(Size index, const Priority& new_priority) {
1181  // check whether the element the priority of which should be changed exists
1182  if (index >= __nb_elements) {
1184  "not enough elements in the PriorityQueueImplementation");
1185  }
1186 
1187  // get the element itself
1188  Val val = __heap[index].second;
1189 
1190  // restore the heap property
1191  Size i = index;
1192 
1193  // move val upward if needed
1194  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
1195  i = j, j = (j - 1) >> 1) {
1196  __heap[i] = std::move(__heap[j]);
1197  __indices[__heap[i].second] = i;
1198  }
1199 
1200  // move val downward if needed
1201  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
1202  // let j be the max child
1203  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
1204  ++j;
1205 
1206  // if "val" is lower than heap[j], "val" must be stored at index i
1207  if (__cmp(new_priority, __heap[j].first)) break;
1208 
1209  // else pull up the jth node
1210  __heap[i] = std::move(__heap[j]);
1211  __indices[__heap[i].second] = i;
1212  }
1213 
1214  // update the index of val
1215  __heap[i].first = new_priority;
1216  __heap[i].second = val;
1217  __indices[val] = i;
1218 
1219  return i;
1220  }
1221 
1222  // changes the size of the internal structure storing the priority queue
1223  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1225  setPriorityByPos(Size index, Priority&& new_priority) {
1226  // check whether the element the priority of which should be changed exists
1227  if (index >= __nb_elements) {
1229  "not enough elements in the PriorityQueueImplementation");
1230  }
1231 
1232  // get the element itself
1233  Val val = __heap[index].second;
1234 
1235  // restore the heap property
1236  Size i = index;
1237 
1238  // move val upward if needed
1239  for (Size j = (i - 1) >> 1; i && __cmp(new_priority, __heap[j].first);
1240  i = j, j = (j - 1) >> 1) {
1241  __heap[i] = std::move(__heap[j]);
1242  __indices[__heap[i].second] = i;
1243  }
1244 
1245  // move val downward if needed
1246  for (Size j = (i << 1) + 1; j < __nb_elements; i = j, j = (j << 1) + 1) {
1247  // let j be the max child
1248  if ((j + 1 < __nb_elements) && __cmp(__heap[j + 1].first, __heap[j].first))
1249  ++j;
1250 
1251  // if "val" is lower than heap[j], "val" must be stored at index i
1252  if (__cmp(new_priority, __heap[j].first)) break;
1253 
1254  // else pull up the jth node
1255  __heap[i] = std::move(__heap[j]);
1256  __indices[__heap[i].second] = i;
1257  }
1258 
1259  // update the index of val
1260  __heap[i].first = std::move(new_priority);
1261  __heap[i].second = val;
1262  __indices[val] = i;
1263 
1264  return i;
1265  }
1266 
1267  // modifies the priority of a given element
1268  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1270  Val elt, const Priority& new_priority) {
1271  setPriorityByPos(__indices[elt], new_priority);
1272  }
1273 
1274  // modifies the priority of a given element
1275  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1277  Val elt, Priority&& new_priority) {
1278  setPriorityByPos(__indices[elt], std::move(new_priority));
1279  }
1280 
1281  // returns the priority of a given element
1282  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1283  INLINE const Priority&
1285  Val elt) const {
1286  return __heap[__indices[elt]].first;
1287  }
1288 
1289  // returns the priority of a given element
1290  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1291  INLINE const Priority&
1293  Size index) const {
1294  if (index > __nb_elements) {
1296  "not enough elements in the PriorityQueueImplementation");
1297  }
1298  return __heap[index].first;
1299  }
1300 
1301  // ===========================================================================
1302  // === PRIORITY QUEUES ===
1303  // ===========================================================================
1304 
1305  // basic constructor
1306  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1308  Size capacity) :
1309  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(cmp, capacity) {
1310  // for debugging purposes
1311  GUM_CONSTRUCTOR(PriorityQueue);
1312  }
1313 
1314  // initializer list constructor
1315  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1317  std::initializer_list< std::pair< Val, Priority > > list) :
1318  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation{list} {
1319  // for debugging purposes
1320  GUM_CONSTRUCTOR(PriorityQueue);
1321  }
1322 
1323  // copy constructor
1324  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1327  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(from) {
1328  // for debugging purposes
1329  GUM_CONS_CPY(PriorityQueue);
1330  }
1331 
1332  // generalized copy constructor
1333  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1334  template < typename OtherAlloc >
1337  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(from) {
1338  // for debugging purposes
1339  GUM_CONS_CPY(PriorityQueue);
1340  }
1341 
1342  // move constructor
1343  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1346  PriorityQueue< Val, Priority, Cmp, Alloc >::Implementation(std::move(from)) {
1347  // for debugging purposes
1348  GUM_CONS_MOV(PriorityQueue);
1349  }
1350 
1351  // destructor
1352  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1354  // for debugging purposes
1355  GUM_DESTRUCTOR(PriorityQueue);
1356  }
1357 
1358  // copy operator
1359  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1363  Implementation::operator=(from);
1364  return *this;
1365  }
1366 
1367  // generalized copy operator
1368  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1369  template < typename OtherAlloc >
1373  Implementation::operator=(from);
1374  return *this;
1375  }
1376 
1377  // move operator
1378  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1382  Implementation::operator=(std::move(from));
1383  return *this;
1384  }
1385 
1386  // A \c << operator for priority queues
1387  template < typename Val, typename Priority, typename Cmp, typename Alloc >
1388  INLINE std::ostream&
1389  operator<<(std::ostream& stream,
1391  stream << queue.toString();
1392  return stream;
1393  }
1394 
1395 } /* namespace gum */
INLINE std::ostream & operator<<(std::ostream &stream, const PriorityQueue< Val, Priority, Cmp, Alloc > &queue)
The internal class for representing priority queues.
Definition: priorityQueue.h:85
STL namespace.
Size __nb_elements
The number of elements in the heap.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
void erase(const Val &val)
Removes a given element from the priority queue (but does not return it).
HashTable< Val, Size, IndexAllocator > __indices
A hashtable for quickly finding the elements by their value.
A priorityQueue is a heap in which each element has a mutable priorityA priority queue is quite simil...
Definition: priorityQueue.h:51
std::vector< std::pair< Priority, const Val *>, HeapAllocator > __heap
An array storing all the elements of the heap as well as their score.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
void resize(Size new_size)
Changes the size of the internal structure storing the priority queue.
void clear()
Removes all the elements from the queue.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
friend class PriorityQueueImplementation
All gum::PriorityQueueImplementation are friends with themselves.
Definition: priorityQueue.h:91
Cmp __cmp
Comparison function.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55